From 565b2263f9e1a62b7a8d0f8070715e486d596f17 Mon Sep 17 00:00:00 2001
From: Wan Muhammad Rayhan Arwindra <wan.muhammad81@ui.ac.id>
Date: Thu, 29 Oct 2020 14:44:52 +0700
Subject: [PATCH] Revert "Merge branch 'pbi3' into 'master'"

This reverts merge request !80
---
 .idea/.gitignore                     |   2 -
 .idea/backend.iml                    |   9 -
 .idea/codeStyles/codeStyleConfig.xml |   5 -
 .idea/encodings.xml                  |   4 -
 .idea/misc.xml                       |   6 -
 .idea/modules.xml                    |   8 -
 .idea/vcs.xml                        |   6 -
 .vscode/launch.json                  |  15 -
 .vscode/settings.json                |   3 -
 api/constants.py                     |  10 -
 api/filters.py                       |   9 -
 api/migrations/0001_initial.py       |  33 +-
 api/models.py                        |  95 +-----
 api/schemas.py                       |  15 -
 api/seeds.py                         |  27 +-
 api/serializers.py                   |  83 +----
 api/signals.py                       |  22 +-
 api/tests.py                         | 440 +++++++++++----------------
 api/urls.py                          |  19 +-
 api/utils.py                         |  34 +--
 api/views.py                         | 193 ++----------
 home_industry/settings/local.py      |   2 +-
 manage.py                            |   0
 23 files changed, 229 insertions(+), 811 deletions(-)
 delete mode 100644 .idea/.gitignore
 delete mode 100644 .idea/backend.iml
 delete mode 100644 .idea/codeStyles/codeStyleConfig.xml
 delete mode 100644 .idea/encodings.xml
 delete mode 100644 .idea/misc.xml
 delete mode 100644 .idea/modules.xml
 delete mode 100644 .idea/vcs.xml
 delete mode 100644 .vscode/launch.json
 delete mode 100644 .vscode/settings.json
 mode change 100644 => 100755 manage.py

diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 5c98b428..00000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-# Default ignored files
-/workspace.xml
\ No newline at end of file
diff --git a/.idea/backend.iml b/.idea/backend.iml
deleted file mode 100644
index d6ebd480..00000000
--- a/.idea/backend.iml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module type="JAVA_MODULE" version="4">
-  <component name="NewModuleRootManager" inherit-compiler-output="true">
-    <exclude-output />
-    <content url="file://$MODULE_DIR$" />
-    <orderEntry type="inheritedJdk" />
-    <orderEntry type="sourceFolder" forTests="false" />
-  </component>
-</module>
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
deleted file mode 100644
index a55e7a17..00000000
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<component name="ProjectCodeStyleConfiguration">
-  <state>
-    <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
-  </state>
-</component>
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
deleted file mode 100644
index 15a15b21..00000000
--- a/.idea/encodings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="Encoding" addBOMForNewFiles="with NO BOM" />
-</project>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 28a804d8..00000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="JavaScriptSettings">
-    <option name="languageLevel" value="ES6" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index e066844e..00000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="ProjectModuleManager">
-    <modules>
-      <module fileurl="file://$PROJECT_DIR$/.idea/backend.iml" filepath="$PROJECT_DIR$/.idea/backend.iml" />
-    </modules>
-  </component>
-</project>
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 35eb1ddf..00000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="VcsDirectoryMappings">
-    <mapping directory="" vcs="Git" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
deleted file mode 100644
index 7a9dfa04..00000000
--- a/.vscode/launch.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-    // Use IntelliSense to learn about possible attributes.
-    // Hover to view descriptions of existing attributes.
-    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
-    "version": "0.2.0",
-    "configurations": [
-        {
-            "type": "pwa-chrome",
-            "request": "launch",
-            "name": "Launch Chrome against localhost",
-            "url": "http://localhost:8080",
-            "webRoot": "${workspaceFolder}"
-        }
-    ]
-}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
deleted file mode 100644
index daa22838..00000000
--- a/.vscode/settings.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-    "python.pythonPath": "env/bin/python3"
-}
\ No newline at end of file
diff --git a/api/constants.py b/api/constants.py
index 17d1bf71..38b00b71 100644
--- a/api/constants.py
+++ b/api/constants.py
@@ -7,16 +7,6 @@ DONATION_STATUS_CHOICES = [
     ('004', _('Waiting for reupload of proof of bank transfer')),
 ]
 
-DONATION_TYPE_CHOICES = [
-    ('CSH', _('Cash')),
-    ('GDS', _('Goods')),
-]
-
-DONATION_GOODS_DELIVERY_METHOD_CHOICES = [
-    ('PCK', _('Pick Up')),
-    ('DLV', _('Delivered')),
-]
-
 PAYMENT_METHOD_CHOICES = [
     ('TRF', _('Transfer')),
     ('COD', _('Cash on delivery')),
diff --git a/api/filters.py b/api/filters.py
index 404d3868..67bfb5db 100644
--- a/api/filters.py
+++ b/api/filters.py
@@ -29,8 +29,6 @@ class TransactionFilter(django_filters.FilterSet):
             'payment_method',
             'transaction_status',
             'updated_at_date_range',
-            'batch_name',
-            'end_date'
         ]
         model = models.Transaction
 
@@ -46,10 +44,3 @@ class ProgramDonationFilter(django_filters.FilterSet):
             'updated_at_date_range',
         ]
         model = models.ProgramDonation
-
-class BatchFilter(django_filters.FilterSet):
-    created_at_date_range = django_filters.DateFromToRangeFilter(field_name='created_at')
-
-    class Meta:
-        fields = ['id', 'batch_name', 'start_date', 'end_date', 'shipping_cost']
-        model = models.Batch
diff --git a/api/migrations/0001_initial.py b/api/migrations/0001_initial.py
index 4eaad886..573f92fd 100644
--- a/api/migrations/0001_initial.py
+++ b/api/migrations/0001_initial.py
@@ -1,4 +1,4 @@
-# Generated by Django 3.0.7 on 2020-10-22 09:08
+# Generated by Django 3.0.7 on 2020-06-06 19:07
 
 import api.utils
 from decimal import Decimal
@@ -85,21 +85,6 @@ class Migration(migrations.Migration):
                 'unique_together': {('bank_name', 'bank_account_number')},
             },
         ),
-        migrations.CreateModel(
-            name='Batch',
-            fields=[
-                ('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False, verbose_name='ID')),
-                ('batch_name', models.CharField(max_length=200, verbose_name='name')),
-                ('start_date', models.DateField(verbose_name='start date')),
-                ('end_date', models.DateField(verbose_name='end date')),
-                ('shipping_cost', models.IntegerField(blank=True, null=True, verbose_name='shipping cost')),
-            ],
-            options={
-                'verbose_name': 'batch',
-                'verbose_name_plural': 'batches',
-                'ordering': ['-start_date', '-end_date', 'batch_name', 'id'],
-            },
-        ),
         migrations.CreateModel(
             name='Category',
             fields=[
@@ -204,10 +189,7 @@ class Migration(migrations.Migration):
                 ('transfer_destination_bank_account_number', models.CharField(blank=True, max_length=100, null=True, verbose_name='transfer destination bank account number')),
                 ('created_at', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='created at')),
                 ('updated_at', models.DateTimeField(auto_now=True, db_index=True, verbose_name='updated at')),
-                ('batch_name', models.CharField(max_length=200, verbose_name='batch name')),
-                ('end_date', models.DateField(null=True, verbose_name='end date')),
                 ('bank_account_transfer_destination', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='transactions', to='api.BankAccountTransferDestination', verbose_name='bank account transfer destination')),
-                ('batch', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='transaction', to='api.Batch', verbose_name='batch')),
                 ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='transactions', to=settings.AUTH_USER_MODEL, verbose_name='user')),
             ],
             options={
@@ -267,22 +249,17 @@ class Migration(migrations.Migration):
                 ('user_full_name', models.CharField(max_length=200, verbose_name='user full name')),
                 ('user_phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region=None, verbose_name='user phone number')),
                 ('program_name', models.CharField(max_length=200, verbose_name='program name')),
-                ('amount', models.DecimalField(blank=True, decimal_places=2, max_digits=12, null=True, validators=[django.core.validators.MinValueValidator(Decimal('0.01'))], verbose_name='amount')),
+                ('amount', models.DecimalField(decimal_places=2, max_digits=12, validators=[django.core.validators.MinValueValidator(Decimal('0.01'))], verbose_name='amount')),
                 ('donation_status', models.CharField(choices=[('001', 'Waiting for admin confirmation'), ('002', 'Completed'), ('003', 'Canceled'), ('004', 'Waiting for reupload of proof of bank transfer')], default='001', max_length=3, verbose_name='donation status')),
-                ('donation_type', models.CharField(choices=[('CSH', 'Cash'), ('GDS', 'Goods')], default='CSH', max_length=3, verbose_name='donation type')),
-                ('proof_of_bank_transfer', models.ImageField(blank=True, null=True, upload_to=api.utils.get_upload_file_path, verbose_name='proof of bank transfer')),
+                ('proof_of_bank_transfer', models.ImageField(upload_to=api.utils.get_upload_file_path, verbose_name='proof of bank transfer')),
                 ('user_bank_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='user bank name')),
-                ('user_bank_account_name', models.CharField(blank=True, max_length=200, null=True, verbose_name='user bank account name')),
+                ('user_bank_account_name', models.CharField(max_length=200, verbose_name='user bank account name')),
                 ('transfer_destination_bank_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='transfer destination bank name')),
                 ('transfer_destination_bank_account_name', models.CharField(blank=True, max_length=200, null=True, verbose_name='transfer destination bank account name')),
                 ('transfer_destination_bank_account_number', models.CharField(blank=True, max_length=100, null=True, verbose_name='transfer destination bank account number')),
-                ('goods_quantity', models.DecimalField(blank=True, decimal_places=0, max_digits=12, null=True, validators=[django.core.validators.MinValueValidator(Decimal('1'))], verbose_name='goods quantity')),
-                ('goods_description', models.CharField(blank=True, max_length=200, null=True, verbose_name='goods description')),
-                ('delivery_method', models.CharField(blank=True, choices=[('PCK', 'Pick Up'), ('DLV', 'Delivered')], max_length=3, null=True, verbose_name='goods delivery method')),
-                ('delivery_address', models.CharField(blank=True, max_length=200, null=True, verbose_name='goods delivery address')),
                 ('created_at', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='created at')),
                 ('updated_at', models.DateTimeField(auto_now=True, db_index=True, verbose_name='updated at')),
-                ('bank_account_transfer_destination', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='program_donations', to='api.BankAccountTransferDestination', verbose_name='bank account transfer destination')),
+                ('bank_account_transfer_destination', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='program_donations', to='api.BankAccountTransferDestination', verbose_name='bank account transfer destination')),
                 ('program', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='program_donations', to='api.Program', verbose_name='program')),
                 ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='program_donations', to=settings.AUTH_USER_MODEL, verbose_name='user')),
             ],
diff --git a/api/models.py b/api/models.py
index 2f56883f..c493722d 100644
--- a/api/models.py
+++ b/api/models.py
@@ -13,8 +13,6 @@ from api import constants, utils
 
 
 class User(auth_models.AbstractUser):
-    REQUIRED_FIELDS=['phone_number']
-
     id = db_models.UUIDField(default=uuid.uuid4, primary_key=True, verbose_name=_('ID'))
     first_name = None
     last_name = None
@@ -305,22 +303,6 @@ class Transaction(db_models.Model):
     )
     updated_at = db_models.DateTimeField(auto_now=True, db_index=True, verbose_name=_('updated at'))
 
-    batch = db_models.ForeignKey(
-            'api.Batch',
-            null=True,
-            blank=True,
-            on_delete=db_models.CASCADE,
-            related_name='transaction',
-            verbose_name=_('batch')
-        )
-
-    batch_name = db_models.CharField(max_length=200, verbose_name=_('batch name'))
-
-    end_date = db_models.DateField(
-        null=True,
-        verbose_name=_('end date')
-    )
-        
     class Meta:
         ordering = ['-updated_at', '-created_at', 'transaction_number', 'id']
         verbose_name = _('transaction')
@@ -443,8 +425,6 @@ class ProgramDonation(db_models.Model):
     user_phone_number = modelfields.PhoneNumberField(verbose_name=_('user phone number'))
     program_name = db_models.CharField(max_length=200, verbose_name=_('program name'))
     amount = db_models.DecimalField(
-        blank=True,
-        null=True,
         decimal_places=2,
         max_digits=12,
         validators=[validators.MinValueValidator(decimal.Decimal('0.01'))],
@@ -456,33 +436,22 @@ class ProgramDonation(db_models.Model):
         max_length=3,
         verbose_name=_('donation status')
     )
-    donation_type = db_models.CharField(
-        choices=constants.DONATION_TYPE_CHOICES,
-        default='CSH',
-        max_length=3,
-        verbose_name=_('donation type')
-    )
     proof_of_bank_transfer = db_models.ImageField(
-        blank=True,
-        null=True,
         upload_to=utils.get_upload_file_path,
         verbose_name=_('proof of bank transfer')
     )
     user_bank_name = db_models.CharField(
         blank=True,
-        null=True,
         max_length=100,
+        null=True,
         verbose_name=_('user bank name')
     )
     user_bank_account_name = db_models.CharField(
-        blank=True,
-        null=True,
         max_length=200,
         verbose_name=_('user bank account name')
     )
     bank_account_transfer_destination = db_models.ForeignKey(
         'api.BankAccountTransferDestination',
-        blank=True,
         null=True,
         on_delete=db_models.SET_NULL,
         related_name='program_donations',
@@ -490,48 +459,21 @@ class ProgramDonation(db_models.Model):
     )
     transfer_destination_bank_name = db_models.CharField(
         blank=True,
-        null=True,
         max_length=100,
+        null=True,
         verbose_name=_('transfer destination bank name')
     )
     transfer_destination_bank_account_name = db_models.CharField(
         blank=True,
-        null=True,
         max_length=200,
+        null=True,
         verbose_name=_('transfer destination bank account name')
     )
     transfer_destination_bank_account_number = db_models.CharField(
         blank=True,
-        null=True,
         max_length=100,
-        verbose_name=_('transfer destination bank account number')
-    )
-    goods_quantity = db_models.DecimalField(
-        blank=True,
-        null=True,
-        decimal_places=0,
-        max_digits=12,
-        validators=[validators.MinValueValidator(decimal.Decimal('1'))],
-        verbose_name=_('goods quantity')
-    )
-    goods_description = db_models.CharField(
-        blank=True,
-        null=True,
-        max_length=200,
-        verbose_name=_('goods description')
-    )
-    delivery_method = db_models.CharField(
-        choices=constants.DONATION_GOODS_DELIVERY_METHOD_CHOICES,
-        blank=True,
         null=True,
-        max_length=3,
-        verbose_name=_('goods delivery method')
-    )
-    delivery_address = db_models.CharField(
-        blank=True,
-        null=True,
-        max_length=200,
-        verbose_name=_('goods delivery address')
+        verbose_name=_('transfer destination bank account number')
     )
     created_at = db_models.DateTimeField(
         auto_now_add=True,
@@ -617,32 +559,3 @@ class ShipmentConfig(solo_models.SingletonModel):
 
     def __str__(self):
         return 'Shipment Configuration'
-
-
-class Batch(db_models.Model):
-    id = db_models.UUIDField(default=uuid.uuid4, primary_key=True, verbose_name=_('ID'))
-    
-    batch_name = db_models.CharField(max_length=200, verbose_name=_('name'))
-
-    start_date = db_models.DateField(
-        blank=False,
-        verbose_name=_('start date')
-    )
-    end_date = db_models.DateField(
-        blank=False,
-        verbose_name=_('end date')
-    )
-
-    shipping_cost = db_models.IntegerField(
-        blank=True,
-        verbose_name=_('shipping cost'),
-        null=True
-    )
-
-    class Meta:
-        ordering = ['-start_date', '-end_date', 'batch_name', 'id']
-        verbose_name = _('batch')
-        verbose_name_plural = _('batches')
-
-    def __str__(self):
-        return self.batch_name
diff --git a/api/schemas.py b/api/schemas.py
index e91a3cbf..1fb99dcf 100644
--- a/api/schemas.py
+++ b/api/schemas.py
@@ -31,17 +31,6 @@ class AutoSchemaWithDateRange(schemas.AutoSchema):
 
 class ReportTransactionSchema(AutoSchemaWithDateRange):
     date_range_fields = ['created_at_date_range']
-    def get_filter_fields(self, path, method):
-        filter_fields = super().get_filter_fields(path, method)
-        filter_fields += [
-            coreapi.Field(
-                'batch_name',
-                location='query',
-                required=False,
-                schema=coreschema.String()
-            )
-        ]
-        return filter_fields
 
 
 class ReportProgramDonationSchema(AutoSchemaWithDateRange):
@@ -54,7 +43,3 @@ class TransactionListSchema(AutoSchemaWithDateRange):
 
 class ProgramDonationListSchema(AutoSchemaWithDateRange):
     date_range_fields = ['updated_at_date_range']
-
-
-class BatchListSchema(AutoSchemaWithDateRange):
-    date_range_fields = ['updated_at_date_range']
\ No newline at end of file
diff --git a/api/seeds.py b/api/seeds.py
index ee45fadb..aff4d005 100644
--- a/api/seeds.py
+++ b/api/seeds.py
@@ -57,24 +57,10 @@ PROGRAM_DATA = {
     'link': 'https://example.com',
 }
 
-PROGRAM_DONATION_CASH_DATA = {
+PROGRAM_DONATION_DATA = {
     'amount': '1000',
-    'user_bank_name': 'Dummy Bank Name',
-    'user_bank_account_name': 'Dummy Bank Account Name',
-}
-
-PROGRAM_DONATION_GOODS_DATA = {
-    'goods_quantity': '10',
-    'goods_description': 'Dummy Goods',
-    'delivery_address': 'Dummy Address',
-    'delivery_method': 'PCK',
-}
-
-PROGRAM_DONATION_GOODS_DATA_DLV = {
-    'goods_quantity': '10',
-    'goods_description': 'Dummy Goods',
-    'delivery_address': None,
-    'delivery_method': 'DLV',
+    'user_bank_name': 'Dummy User Bank Name',
+    'user_bank_account_name': 'Dummy User Bank Account Name',
 }
 
 HELP_CONTACT_CONFIG_DATA = {
@@ -89,10 +75,3 @@ SHIPMENT_CONFIG_DATA = {
     'same_urban_village_different_hamlet_costs': '2000',
     'same_sub_district_different_urban_village_costs': '3000',
 }
-
-BATCH_DATA = {
-    'batch_name': 'Batch 1',
-    'start_date': '2020-10-08',
-    'end_date': '2020-10-15',
-    'shipping_cost': '60000',
-}
\ No newline at end of file
diff --git a/api/serializers.py b/api/serializers.py
index 290967f2..157f7aa4 100644
--- a/api/serializers.py
+++ b/api/serializers.py
@@ -58,53 +58,23 @@ class CartCompleteOrCancelTransactionSerializer(serializers.Serializer): # pylin
 
 class DonationCreateSerializer(serializers.Serializer): # pylint: disable=abstract-method
     program = serializers.UUIDField(label=_('Program'))
-    donation_type = serializers.ChoiceField(
-        choices=constants.DONATION_TYPE_CHOICES,
-        label=_('Donation type')
-    )
     amount = serializers.DecimalField(
         decimal_places=2,
         label=_('Amount'),
         max_digits=12,
-        min_value=decimal.Decimal('0.01'),
-        required=False
+        min_value=decimal.Decimal('0.01')
     )
     proof_of_bank_transfer = serializers.ImageField(label=_('Proof of bank transfer'))
     user_bank_name = serializers.CharField(
         label=_('User bank name'),
-        max_length=100,
-        required=False
+        max_length=100
     )
     user_bank_account_name = serializers.CharField(
         label=_('User bank account name'),
-        max_length=200,
-        required=False
+        max_length=200
     )
     bank_account_transfer_destination = serializers.UUIDField(
-        label=_('Bank account transfer destination'),
-        required=False
-    )
-    goods_quantity = serializers.DecimalField(
-        decimal_places=0,
-        label=_('Goods quantity'),
-        max_digits=12,
-        min_value=decimal.Decimal('1'),
-        required=False
-    )
-    goods_description = serializers.CharField(
-        label=_('Goods description'),
-        max_length=200,
-        required=False
-    )
-    delivery_method = serializers.ChoiceField(
-        choices=constants.DONATION_GOODS_DELIVERY_METHOD_CHOICES,
-        label=_('Goods delivery method'),
-        required=False
-    )
-    delivery_address = serializers.CharField(
-        label=_('Goods delivery address'),
-        max_length=200,
-        required=False
+        label=_('Bank account transfer destination')
     )
 
 
@@ -329,11 +299,10 @@ class TransactionSerializer(serializers.ModelSerializer):
     readable_transaction_status = serializers.SerializerMethodField(
         'get_readable_transaction_status'
     )
-    
     transaction_items = TransactionItemSerializer(many=True, read_only=True)
     transaction_item_subtotal = serializers.SerializerMethodField('get_transaction_item_subtotal')
     subtotal = serializers.SerializerMethodField('get_subtotal')
-    
+
     class Meta:
         fields = [
             'id',
@@ -365,9 +334,6 @@ class TransactionSerializer(serializers.ModelSerializer):
             'transaction_items',
             'transaction_item_subtotal',
             'subtotal',
-            'batch',
-            'batch_name',
-            'end_date'
         ]
         model = models.Transaction
         read_only_fields = [
@@ -393,9 +359,6 @@ class TransactionSerializer(serializers.ModelSerializer):
             'transfer_destination_bank_account_number',
             'created_at',
             'updated_at',
-            'batch',
-            'batch_name',
-            'end_date'
         ]
 
     def get_readable_payment_method(self, obj): # pylint: disable=no-self-use
@@ -451,8 +414,7 @@ class ProgramSerializer(serializers.ModelSerializer):
     def get_total_donation_amount(self, obj): # pylint: disable=no-self-use
         total_donation_amount = sum(
             program_donation.amount for program_donation in obj.program_donations.filter(
-                donation_status='002',
-                donation_type='CSH'
+                donation_status='002'
             )
         )
         return str(total_donation_amount)
@@ -488,9 +450,8 @@ class ProgramDonationSerializer(serializers.ModelSerializer):
             'user_full_name',
             'user_phone_number',
             'program_name',
-            'donation_type',
-            'donation_status',
             'amount',
+            'donation_status',
             'readable_donation_status',
             'proof_of_bank_transfer',
             'user_bank_name',
@@ -499,10 +460,6 @@ class ProgramDonationSerializer(serializers.ModelSerializer):
             'transfer_destination_bank_name',
             'transfer_destination_bank_account_name',
             'transfer_destination_bank_account_number',
-            'goods_quantity',
-            'goods_description',
-            'delivery_method',
-            'delivery_address',
             'created_at',
             'updated_at',
         ]
@@ -515,7 +472,6 @@ class ProgramDonationSerializer(serializers.ModelSerializer):
             'user_full_name',
             'user_phone_number',
             'program_name',
-            'donation_type',
             'amount',
             'proof_of_bank_transfer',
             'user_bank_name',
@@ -555,28 +511,3 @@ class ShipmentConfigSerializer(serializers.ModelSerializer):
             'same_sub_district_different_urban_village_costs',
         ]
         model = models.ShipmentConfig
-
-class BatchSerializer(serializers.ModelSerializer):
-    class Meta:
-        fields = [
-            'id',
-            'batch_name',
-            'start_date',
-            'end_date',
-            'shipping_cost'
-        ]
-        model = models.Batch
-
-class BatchCreateSerializer(serializers.Serializer): # pylint: disable=abstract-method
-    batch_name = serializers.CharField(
-        label=_('Batch name'),
-        max_length=200
-    )
-    start_date = serializers.DateField(label=_('Start Date'))
-    end_date = serializers.DateField(label=_('End Date'))
-    shipping_cost = serializers.DecimalField(
-        decimal_places=2,
-        label=_('Amount'),
-        max_digits=12,
-        min_value=decimal.Decimal('0.01')
-    )
diff --git a/api/signals.py b/api/signals.py
index 528d5ce2..fe0a2e28 100644
--- a/api/signals.py
+++ b/api/signals.py
@@ -3,6 +3,7 @@ from django.db.models import signals
 
 from api import models, utils
 
+
 @dispatch.receiver(signals.post_save, sender=models.User)
 def create_shopping_cart(sender, created, instance, **_kwargs): # pylint: disable=unused-argument
     if created:
@@ -51,12 +52,6 @@ def fill_dependent_transaction_fields(sender, instance, **_kwargs):
             instance.transfer_destination_bank_account_number = (
                 instance.bank_account_transfer_destination.bank_account_number
             )
-            
-    if (obj is not None) and (instance.transaction_status == '002'):
-        if instance.batch is None:
-            instance.batch = utils.get_batch_transaction(instance)
-        instance.batch_name = instance.batch.batch_name
-        instance.end_date = instance.batch.end_date
 
 
 @dispatch.receiver(signals.pre_save, sender=models.TransactionItem)
@@ -100,11 +95,14 @@ def fill_dependent_program_donation_fields(sender, instance, **_kwargs):
         else:
             instance.user_full_name = instance.user.full_name
             instance.user_phone_number = instance.user.phone_number
-    
-    if (obj is not None) and (instance.donation_type != None):
-        if (instance.donation_type=='CSH'):
-            if (instance.bank_account_transfer_destination is None):
-                instance.bank_account_transfer_destination= utils.get_transfer_destination(instance)
+    if ((obj is None) or
+            (obj.bank_account_transfer_destination != instance.bank_account_transfer_destination)
+            or (getattr(instance, 'update_bank_account_transfer_destination', False))):
+        if instance.bank_account_transfer_destination is None:
+            instance.transfer_destination_bank_name = None
+            instance.transfer_destination_bank_account_name = None
+            instance.transfer_destination_bank_account_number = None
+        else:
             instance.transfer_destination_bank_name = (
                 instance.bank_account_transfer_destination.bank_name
             )
@@ -113,4 +111,4 @@ def fill_dependent_program_donation_fields(sender, instance, **_kwargs):
             )
             instance.transfer_destination_bank_account_number = (
                 instance.bank_account_transfer_destination.bank_account_number
-            )
\ No newline at end of file
+            )
diff --git a/api/tests.py b/api/tests.py
index d5f35df0..a0e3dc04 100644
--- a/api/tests.py
+++ b/api/tests.py
@@ -1,13 +1,13 @@
 import decimal
 import tempfile
 from unittest import mock
-import datetime
+
 import jwt
 from django import conf, test as django_test, urls
 from django.core import management
 from PIL import Image
 from rest_framework import exceptions, status, test as rest_framework_test
-from django.utils import timezone
+
 from api import models, seeds, utils, views
 
 
@@ -148,22 +148,6 @@ class UtilsTest(django_test.TestCase):
         self.assertIsInstance(mapped_choices, list)
         self.assertEqual(len(mapped_choices), len(choices))
 
-    def get_batch_transaction_success(self):
-        transaction = models.Transaction.objects.create(**seeds.TRANSACTION_DATA)
-        transaction.created_at= datetime.datetime.now()
-        batch = models.Batch.objects.create(**seeds.BATCH_DATA)
-        batch_transaction=utils.get_batch_transaction(transaction)
-        self.assertEqual(batch.batch_name,batch_transaction.batch_name)
-
-    def get_batch_transaction_fail(self):
-        transaction = models.Transaction.objects.create(**seeds.TRANSACTION_DATA)
-        transaction.created_at= datetime.datetime.now()
-        batch = models.Batch.objects.create('Batch 2','2020-10-08','2020-10-08',19000)
-        batch_transaction=utils.get_batch_transaction(transaction)
-        self.assertEqual(None,batch_transaction.batch_name)
-    
-
-
 
 class AuthTest(rest_framework_test.APITestCase):
     def setUp(self):
@@ -401,7 +385,7 @@ class CartTest(rest_framework_test.APITestCase): # pylint: disable=too-many-inst
         )
         self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
         self.assertEqual(models.Transaction.objects.count(), 0)
-        
+
     def test_cart_complete_transaction(self):
         data = {
             'product': self.product.id,
@@ -443,8 +427,6 @@ class CartTest(rest_framework_test.APITestCase): # pylint: disable=too-many-inst
             http_authorization=self.user_http_authorization
         )
         self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
-        self.assertEqual(transaction.batch, None)
-
 
     def test_cart_cancel_transaction(self):
         data = {
@@ -485,6 +467,44 @@ class CartTest(rest_framework_test.APITestCase): # pylint: disable=too-many-inst
         )
         self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
 
+    def test_cart_upload_pop_success(self):
+        data = {
+            'product': self.product.id,
+            'quantity': 1,
+        }
+        request(
+            'POST',
+            'cart-update',
+            data,
+            http_authorization=self.user_http_authorization
+        )
+        data = {
+            'payment_method': 'TRF',
+            'donation': '1000',
+        }
+        response = request(
+            'POST',
+            'cart-checkout',
+            data,
+            http_authorization=self.user_http_authorization
+        )
+        with open(self.proof_of_payment_file.name, 'rb') as proof_of_payment:
+            data = {
+                'transaction': response.data['transaction'],
+                'proof_of_payment': proof_of_payment,
+                'user_bank_name': 'Dummy User Bank Name',
+                'user_bank_account_name': 'Dummy User Bank Account Name',
+                'bank_account_transfer_destination': self.bank_account_transfer_destination.id,
+            }
+            response = request(
+                'POST',
+                'cart-upload-pop',
+                data,
+                format='multipart',
+                http_authorization=self.user_http_authorization
+            )
+            self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
+
     def test_cart_upload_pop_fail(self):
         data = {
             'product': self.product.id,
@@ -506,6 +526,22 @@ class CartTest(rest_framework_test.APITestCase): # pylint: disable=too-many-inst
             data,
             http_authorization=self.user_http_authorization
         )
+        with open(self.proof_of_payment_file.name, 'rb') as proof_of_payment:
+            data = {
+                'transaction': response.data['transaction'],
+                'proof_of_payment': proof_of_payment,
+                'user_bank_name': 'Dummy User Bank Name',
+                'user_bank_account_name': 'Dummy User Bank Account Name',
+                'bank_account_transfer_destination': self.bank_account_transfer_destination.id,
+            }
+            response = request(
+                'POST',
+                'cart-upload-pop',
+                data,
+                format='multipart',
+                http_authorization=self.user_http_authorization
+            )
+            self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
         data = {
             'product': self.product.id,
             'quantity': 1,
@@ -529,6 +565,22 @@ class CartTest(rest_framework_test.APITestCase): # pylint: disable=too-many-inst
         transaction = models.Transaction.objects.get(id=response.data['transaction'])
         transaction.transaction_status = '003'
         transaction.save()
+        with open(self.proof_of_payment_file.name, 'rb') as proof_of_payment:
+            data = {
+                'transaction': response.data['transaction'],
+                'proof_of_payment': proof_of_payment,
+                'user_bank_name': 'Dummy User Bank Name',
+                'user_bank_account_name': 'Dummy User Bank Account Name',
+                'bank_account_transfer_destination': self.bank_account_transfer_destination.id,
+            }
+            response = request(
+                'POST',
+                'cart-upload-pop',
+                data,
+                format='multipart',
+                http_authorization=self.user_http_authorization
+            )
+            self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
 
     @mock.patch('api.utils.validate_product_stock', return_value=None)
     def test_cart_checkout_race_condition(self, mock_validate_product_stock):
@@ -556,7 +608,7 @@ class CartTest(rest_framework_test.APITestCase): # pylint: disable=too-many-inst
         self.assertEqual(mock_validate_product_stock.call_count, 1)
 
 
-class DonationCashTest(rest_framework_test.APITestCase):
+class DonationTest(rest_framework_test.APITestCase):
     def setUp(self):
         self.user = create_user(seeds.USER_DATA)
         self.user_http_authorization = get_http_authorization(
@@ -569,67 +621,102 @@ class DonationCashTest(rest_framework_test.APITestCase):
             )
         )
         self.proof_of_bank_transfer_file = create_tmp_image()
-        
-    
-    def test_donation_reupload_proof_of_bank_transfer_success(self):
+
+    def test_donation_create_success(self):
         program = models.Program.objects.create(**seeds.PROGRAM_DATA)
-        program_donation = models.ProgramDonation.objects.create(**dict(
-            seeds.PROGRAM_DONATION_CASH_DATA,
-            user=self.user,
-            program=program
-        ))
-        program_donation.save()
+        with open(self.proof_of_bank_transfer_file.name, 'rb') as proof_of_bank_transfer:
+            data = {
+                'program': program.id,
+                'amount': '1000',
+                'proof_of_bank_transfer': proof_of_bank_transfer,
+                'user_bank_name': 'Dummy User Bank Name',
+                'user_bank_account_name': 'Dummy User Bank Account Name',
+                'bank_account_transfer_destination': self.bank_account_transfer_destination.id,
+            }
+            response = request(
+                'POST',
+                'donation-create',
+                data,
+                format='multipart',
+                http_authorization=self.user_http_authorization
+            )
+            self.assertEqual(response.status_code, status.HTTP_200_OK)
+            self.assertEqual(models.ProgramDonation.objects.count(), 1)
 
-    def test_donation_reupload_proof_of_bank_transfer_fail(self):
+    def test_donation_create_fail(self):
         program = models.Program.objects.create(**seeds.PROGRAM_DATA)
-        program_donation = models.ProgramDonation.objects.create(**dict(
-            seeds.PROGRAM_DONATION_CASH_DATA,
-            user=self.user,
-            program=program
-        ))
-        program_donation.donation_status = '002'
-        program_donation.save()
+        program.open_donation = False
+        program.save()
+        with open(self.proof_of_bank_transfer_file.name, 'rb') as proof_of_bank_transfer:
+            data = {
+                'program': program.id,
+                'amount': '1000',
+                'proof_of_bank_transfer': proof_of_bank_transfer,
+                'user_bank_name': 'Dummy User Bank Name',
+                'user_bank_account_name': 'Dummy User Bank Account Name',
+                'bank_account_transfer_destination': self.bank_account_transfer_destination.id,
+            }
+            response = request(
+                'POST',
+                'donation-create',
+                data,
+                format='multipart',
+                http_authorization=self.user_http_authorization
+            )
+            self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+            self.assertEqual(models.ProgramDonation.objects.count(), 0)
 
-class DonationDeliveryTest(rest_framework_test.APITestCase):
-    def setUp(self):
-        self.user = create_user(seeds.USER_DATA)
-        self.user_http_authorization = get_http_authorization(
-            seeds.USER_DATA['username'],
-            seeds.USER_DATA['password']
-        )
-        
-    
-    def test_donation_goods_create_success(self):
+    def test_donation_reupload_proof_of_bank_transfer_success(self):
         program = models.Program.objects.create(**seeds.PROGRAM_DATA)
         program_donation = models.ProgramDonation.objects.create(**dict(
-            seeds.PROGRAM_DONATION_GOODS_DATA,
+            seeds.PROGRAM_DONATION_DATA,
             user=self.user,
-            program=program,
+            program=program
         ))
-        program_donation.donation_type='GDS'
-        program_donation.save()
+        with open(self.proof_of_bank_transfer_file.name, 'rb') as proof_of_bank_transfer:
+            data = {
+                'amount': '1000',
+                'program_donation': program_donation.id,
+                'proof_of_bank_transfer': proof_of_bank_transfer,
+                'user_bank_name': 'Dummy User Bank Name',
+                'user_bank_account_name': 'Dummy User Bank Account Name',
+                'bank_account_transfer_destination': self.bank_account_transfer_destination.id,
+            }
+            response = request(
+                'POST',
+                'donation-reupload-proof-of-bank-transfer',
+                data,
+                format='multipart',
+                http_authorization=self.user_http_authorization
+            )
+            self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
 
-    def test_donation_goods_create_fail(self):
+    def test_donation_reupload_proof_of_bank_transfer_fail(self):
         program = models.Program.objects.create(**seeds.PROGRAM_DATA)
         program_donation = models.ProgramDonation.objects.create(**dict(
-            seeds.PROGRAM_DONATION_GOODS_DATA,
+            seeds.PROGRAM_DONATION_DATA,
             user=self.user,
-            program=program,
+            program=program
         ))
-        program_donation.donation_type='GDS'
         program_donation.donation_status = '002'
         program_donation.save()
-
-    def test_delivery_method(self):
-        program = models.Program.objects.create(**seeds.PROGRAM_DATA)
-        program_donation = models.ProgramDonation.objects.create(**dict(
-            seeds.PROGRAM_DONATION_GOODS_DATA_DLV,
-            user=self.user,
-            program=program,
-        ))
-        program_donation.donation_type='GDS'
-        self.assertEqual(program_donation.delivery_address,None)
-        self.assertEqual(program_donation.delivery_method,'DLV')
+        with open(self.proof_of_bank_transfer_file.name, 'rb') as proof_of_bank_transfer:
+            data = {
+                'amount': '1000',
+                'program_donation': program_donation.id,
+                'proof_of_bank_transfer': proof_of_bank_transfer,
+                'user_bank_name': 'Dummy User Bank Name',
+                'user_bank_account_name': 'Dummy User Bank Account Name',
+                'bank_account_transfer_destination': self.bank_account_transfer_destination.id,
+            }
+            response = request(
+                'POST',
+                'donation-reupload-proof-of-bank-transfer',
+                data,
+                format='multipart',
+                http_authorization=self.user_http_authorization
+            )
+            self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
 
 
 class ReportViewsTest(rest_framework_test.APITestCase):
@@ -640,8 +727,6 @@ class ReportViewsTest(rest_framework_test.APITestCase):
             seeds.SUPERUSER_DATA['password']
         )
         models.ShipmentConfig.objects.create(**seeds.SHIPMENT_CONFIG_DATA)
-        models.Batch.objects.create(**seeds.BATCH_DATA)
-        models.BankAccountTransferDestination.objects.create(**seeds.BANK_ACCOUNT_TRANSFER_DESTINATION)
 
     def test_get_filename_not_implemented_error(self):
         with self.assertRaises(NotImplementedError):
@@ -686,7 +771,7 @@ class ReportViewsTest(rest_framework_test.APITestCase):
         user = create_user(seeds.USER_DATA)
         program = models.Program.objects.create(**seeds.PROGRAM_DATA)
         program_donation = models.ProgramDonation.objects.create(**dict(
-            seeds.PROGRAM_DONATION_CASH_DATA,
+            seeds.PROGRAM_DONATION_DATA,
             user=user,
             program=program
         ))
@@ -1275,8 +1360,6 @@ class TransactionTest(rest_framework_test.APITestCase):
             seeds.USER_DATA['username'],
             seeds.USER_DATA['password']
         )
-        self.batch = models.Batch.objects.create(**seeds.BATCH_DATA)
-        
 
     def test_transaction_model_string_representation(self):
         transaction = models.Transaction.objects.create(**dict(
@@ -1369,7 +1452,6 @@ class TransactionItemTest(rest_framework_test.APITestCase):
             seeds.SUPERUSER_DATA['username'],
             seeds.SUPERUSER_DATA['password']
         )
-        models.Batch.objects.create(**seeds.BATCH_DATA)
         models.ShipmentConfig.objects.create(**seeds.SHIPMENT_CONFIG_DATA)
         self.user = create_user(seeds.USER_DATA)
         self.category = models.Category.objects.create(**seeds.CATEGORY_DATA)
@@ -1385,7 +1467,6 @@ class TransactionItemTest(rest_framework_test.APITestCase):
             seeds.TRANSACTION_DATA,
             user=self.user
         ))
-        
 
     def test_transaction_item_model_string_representation(self):
         transaction_item = models.TransactionItem.objects.create(**dict(
@@ -1485,6 +1566,20 @@ class ProgramTest(rest_framework_test.APITestCase):
             url_args=[program.id]
         )
         self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+        program_minutes_file = create_tmp_image()
+        with open(program_minutes_file.name, 'rb') as program_minutes_file:
+            data = {
+                'program_minutes': program_minutes_file,
+            }
+            response = request(
+                'PATCH',
+                'program-detail',
+                data,
+                format='multipart',
+                http_authorization=self.superuser_http_authorization,
+                url_args=[program.id]
+            )
+            self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
 
 
 class ProgramDonationTest(rest_framework_test.APITestCase):
@@ -1500,16 +1595,15 @@ class ProgramDonationTest(rest_framework_test.APITestCase):
             seeds.USER_DATA['password']
         )
         self.program = models.Program.objects.create(**seeds.PROGRAM_DATA)
-        models.BankAccountTransferDestination.objects.create(**seeds.BANK_ACCOUNT_TRANSFER_DESTINATION)
 
     def test_program_donation_model_string_representation(self):
         program_donation = models.ProgramDonation.objects.create(**dict(
-            seeds.PROGRAM_DONATION_CASH_DATA,
+            seeds.PROGRAM_DONATION_DATA,
             user=self.user,
             program=self.program
         ))
         self.assertEqual(len(str(program_donation)), 6)
-    
+
     def test_program_donation_list_success(self):
         response = request(
             'GET',
@@ -1517,27 +1611,16 @@ class ProgramDonationTest(rest_framework_test.APITestCase):
             http_authorization=self.superuser_http_authorization,
         )
         self.assertEqual(response.status_code, status.HTTP_200_OK)
-    
-
-    def test_program_donation_csh_list_success(self):
         response = request(
             'GET',
-            'program-donation-csh-list',
-            http_authorization=self.superuser_http_authorization,
-        )
-        self.assertEqual(response.status_code, status.HTTP_200_OK)
-        
-    def test_program_donation_gds_list_success(self):
-        response = request(
-            'GET',
-            'program-donation-gds-list',
+            'program-donation-list',
             http_authorization=self.user_http_authorization,
         )
         self.assertEqual(response.status_code, status.HTTP_200_OK)
 
     def test_program_donation_detail_success(self):
         program_donation = models.ProgramDonation.objects.create(**dict(
-            seeds.PROGRAM_DONATION_CASH_DATA,
+            seeds.PROGRAM_DONATION_DATA,
             user=self.user,
             program=self.program
         ))
@@ -1551,10 +1634,10 @@ class ProgramDonationTest(rest_framework_test.APITestCase):
 
     def test_update_program_donation_success(self):
         program_donation = models.ProgramDonation.objects.create(**dict(
-            seeds.PROGRAM_DONATION_CASH_DATA,
+            seeds.PROGRAM_DONATION_DATA,
             user=self.user,
             program=self.program
-        )) 
+        ))
         data = {
             'donation_status': '002',
         }
@@ -1573,7 +1656,7 @@ class ProgramDonationTest(rest_framework_test.APITestCase):
 
     def test_update_program_donation_fail(self):
         program_donation = models.ProgramDonation.objects.create(**dict(
-            seeds.PROGRAM_DONATION_CASH_DATA,
+            seeds.PROGRAM_DONATION_DATA,
             user=self.user,
             program=self.program
         ))
@@ -1772,172 +1855,3 @@ class ShipmentConfigTest(rest_framework_test.APITestCase):
             http_authorization=self.superuser_http_authorization
         )
         self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-
-class CategoryTest(rest_framework_test.APITestCase):
-    def setUp(self):
-        self.superuser = models.User.objects.create_superuser(**seeds.SUPERUSER_DATA)
-        self.superuser_http_authorization = get_http_authorization(
-            seeds.SUPERUSER_DATA['username'],
-            seeds.SUPERUSER_DATA['password']
-        )
-
-    def test_category_model_string_representation(self):
-        category = models.Category.objects.create(**seeds.CATEGORY_DATA)
-        self.assertEqual(str(category), seeds.CATEGORY_DATA['name'])
-
-    def test_category_list_success(self):
-        response = request(
-            'GET',
-            'category-list',
-            http_authorization=self.superuser_http_authorization
-        )
-        self.assertEqual(response.status_code, status.HTTP_200_OK)
-
-    def test_category_detail_success(self):
-        category = models.Category.objects.create(**seeds.CATEGORY_DATA)
-        response = request(
-            'GET',
-            'category-detail',
-            http_authorization=self.superuser_http_authorization,
-            url_args=[category.id]
-        )
-        self.assertEqual(response.status_code, status.HTTP_200_OK)
-
-    def test_create_category_success(self):
-        data = seeds.CATEGORY_DATA
-        response = request(
-            'POST',
-            'category-list',
-            data,
-            http_authorization=self.superuser_http_authorization
-        )
-        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
-        self.assertEqual(models.Category.objects.count(), 1)
-        self.assertEqual(models.Category.objects.get(id=response.data['id']).name, data['name'])
-
-    def test_create_category_fail(self):
-        response = request(
-            'POST',
-            'category-list',
-            http_authorization=self.superuser_http_authorization
-        )
-        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertEqual(models.Category.objects.count(), 0)
-
-    def test_delete_category_success(self):
-        category = models.Category.objects.create(**seeds.CATEGORY_DATA)
-        response = request(
-            'DELETE',
-            'category-detail',
-            http_authorization=self.superuser_http_authorization,
-            url_args=[category.id]
-        )
-        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
-        self.assertEqual(models.Category.objects.count(), 0)
-
-    def test_delete_category_fail(self):
-        category = models.Category.objects.create(**seeds.CATEGORY_DATA)
-        subcategory = models.Subcategory.objects.create(**dict(
-            seeds.SUBCATEGORY_DATA, category=category
-        ))
-        models.Product.objects.create(**dict(seeds.PRODUCT_DATA, subcategory=subcategory))
-        response = request(
-            'DELETE',
-            'category-detail',
-            http_authorization=self.superuser_http_authorization,
-            url_args=[category.id]
-        )
-        self.assertEqual(response.status_code, status.HTTP_409_CONFLICT)
-        self.assertEqual(models.Category.objects.count(), 1)
-
-class BatchTest(rest_framework_test.APITestCase):
-    def setUp(self):
-        self.superuser = models.User.objects.create_superuser(**seeds.SUPERUSER_DATA)
-        self.superuser_http_authorization = get_http_authorization(
-            seeds.SUPERUSER_DATA['username'],
-            seeds.SUPERUSER_DATA['password']
-        )
-
-    def test_batch_model_string_representation(self):
-        batch = models.Batch.objects.create(**seeds.BATCH_DATA)
-        self.assertEqual(str(batch), seeds.BATCH_DATA['batch_name'])
-
-    def test_batch_list_success(self):
-        response = request(
-            'GET',
-            'batch-list',
-            http_authorization=self.superuser_http_authorization
-        )
-        self.assertEqual(response.status_code, status.HTTP_200_OK)
-
-    def test_create_batch_success(self):
-        data = seeds.BATCH_DATA
-        response = request(
-            'POST',
-            'batch-list',
-            data,
-            http_authorization=self.superuser_http_authorization
-        )
-        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
-        self.assertEqual(models.Batch.objects.count(), 1)
-        self.assertEqual(models.Batch.objects.get(id=response.data['id']).batch_name, data['batch_name'])
-
-    def test_create_batch_fail(self):
-        data = {
-            'batch_name': 'Batch 1',
-            'start_date': '2020-10-15',
-            'end_date': '',
-            'shipping_cost': '60000',
-        }
-        response = request(
-            'POST',
-            'batch-list',
-            data,
-            http_authorization=self.superuser_http_authorization
-        )
-        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
-        self.assertEqual(models.Batch.objects.count(), 0)
-
-    def test_create_batch_wrong_date(self):
-        data = {
-            'batch_name': 'Batch 1',
-            'start_date': '2020-10-15',
-            'end_date': '2020-10-8',
-            'shipping_cost': '60000',
-        }
-        response = request(
-            'POST',
-            'batch-list',
-            data,
-            http_authorization=self.superuser_http_authorization
-        )
-        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
-        self.assertEqual(models.Batch.objects.count(), 0)
-        
-    def test_edit_batch_success(self):
-        batch = models.Batch.objects.create(**seeds.BATCH_DATA)
-        data = seeds.BATCH_DATA
-        data['shipping_cost'] = 30000
-        response = request(
-            'PATCH',
-            'batch-detail',
-            data,
-            url_args=[batch.id],
-            http_authorization=self.superuser_http_authorization
-        )
-        self.assertEqual(response.status_code, status.HTTP_200_OK)
-        self.assertEqual(models.Batch.objects.get(id=batch.id).shipping_cost, data['shipping_cost'])
-
-    def test_edit_batch_fail(self):
-        batch = models.Batch.objects.create(**seeds.BATCH_DATA)
-        data = seeds.BATCH_DATA
-        data['shipping_cost'] = 30000
-        response = request(
-            'PATCH',
-            'batch-detail',
-            data,
-            url_args=[0],
-            http_authorization=self.superuser_http_authorization
-        )
-        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
-        self.assertEqual(models.Batch.objects.get(id=batch.id).shipping_cost, 60000)
diff --git a/api/urls.py b/api/urls.py
index 9d3412f4..bfe3cc10 100644
--- a/api/urls.py
+++ b/api/urls.py
@@ -37,9 +37,9 @@ urlpatterns = [
     ),
     urls.path(
         'reports/transaction/',
-            api_views.ReportTransaction.as_view(),
-            name='transaction-report'
-        ),
+        api_views.ReportTransaction.as_view(),
+        name='transaction-report'
+    ),
     urls.path(
         'reports/program-donation/',
         api_views.ReportProgramDonation.as_view(),
@@ -81,16 +81,6 @@ urlpatterns = [
     ),
     urls.path('programs/', api_views.ProgramList.as_view(), name='program-list'),
     urls.path('programs/<str:pk>/', api_views.ProgramDetail.as_view(), name='program-detail'),
-    urls.path(
-        'program-donations/csh',
-        api_views.ProgramDonationListCSH.as_view(),
-        name='program-donation-csh-list'
-    ),
-    urls.path(
-        'program-donations/gds',
-        api_views.ProgramDonationListGDS.as_view(),
-        name='program-donation-gds-list'
-    ),
     urls.path(
         'program-donations/',
         api_views.ProgramDonationList.as_view(),
@@ -127,7 +117,4 @@ urlpatterns = [
         api_views.ShipmentConfigDetail.as_view(),
         name='shipment-config-detail'
     ),
-    urls.path('batch/', api_views.BatchList.as_view(), name='batch-list'),
-    urls.path('batch/<str:pk>/', api_views.BatchDetail.as_view(), name='batch-detail'),
-    urls.path('batch/create/', api_views.BatchCreate.as_view(), name='batch-create'),
 ]
diff --git a/api/utils.py b/api/utils.py
index d269b5cf..20d8b163 100644
--- a/api/utils.py
+++ b/api/utils.py
@@ -1,15 +1,13 @@
 import datetime
-from datetime import timedelta
+
 import jwt
 import shortuuid
 from jwt import exceptions as jwt_exceptions
 from django import conf
-from django.utils import timezone
 from django.utils.translation import gettext_lazy as _
 from rest_framework import exceptions as rest_framework_exceptions
 
 from home_industry import utils
-from api import models
 
 
 def generate_bearer_token(user):
@@ -117,33 +115,3 @@ def validate_product_stock(cart_items):
                 'Failed to checkout because the purchased quantity of certain items exceeds the '
                 'available stock.'
             ))
-
-
-def get_batch_transaction(transaction):
-    today = timezone.now().date()
-    transaction_batch = models.Batch.objects.filter(start_date__lte=date, end_date__gt=date).first()
-    if transaction_batch is None:
-        days_to_saturday = 5 - today.weekday()
-        if days_to_saturday == -1:
-            end_date = today + timedelta(days=6)
-            start_date = end_date - timedelta(days=7)
-        else:
-            end_date = today + timedelta(days=days_to_saturday)
-            start_date = end_date - timedelta(days=7)
-        transaction_batch = models.Batch.objects.create(
-            batch_name='Auto Batch',
-            start_date=start_date,
-            end_date=end_date,
-            shipping_cost=0
-        )
-        transaction_batch.save()
-    return transaction_batch
-
-def get_transfer_destination(program_donation):
-    bank_name= program_donation.user_bank_name
-    bank_account_name= program_donation.user_bank_account_name
-    transfer_destination=None
-    for bank_destination in models.BankAccountTransferDestination.objects.all():
-        if (bank_destination.bank_name== bank_name) and (bank_destination.bank_account_name== bank_account_name):
-            transfer_destination= bank_destination
-    return transfer_destination
diff --git a/api/views.py b/api/views.py
index 3c0e09eb..cfcfecdc 100644
--- a/api/views.py
+++ b/api/views.py
@@ -1,4 +1,3 @@
-
 from django import http, shortcuts
 from django.contrib import auth
 from django.db import transaction as db_transaction, utils as db_utils
@@ -172,17 +171,12 @@ class CartCheckout(rest_framework_views.APIView):
         transaction_status = (
             '001' if serializer.validated_data['payment_method'] == 'TRF' else '002'
         )
-        batch = (
-            None if serializer.validated_data['payment_method'] == 'TRF'
-            else models.Batch.objects.filter(start_date__lte=timezone.now().date(), end_date__gte=timezone.now().date()).first()
-        )
         transaction = models.Transaction.objects.create(
             user=user,
             payment_method=serializer.validated_data['payment_method'],
             donation=serializer.validated_data['donation'],
-            transaction_status=transaction_status,
+            transaction_status=transaction_status
         )
-        
         is_success = True
         for cart_item in cart_items:
             product = cart_item.product
@@ -240,7 +234,6 @@ class CartUploadPOP(rest_framework_views.APIView):
         transaction.bank_account_transfer_destination = bank_account_transfer_destination
         transaction.update_bank_account_transfer_destination = True
         transaction.transaction_status = '002'
-        transaction.batch = models.Batch.objects.filter(start_date__lte=timezone.now().date(), end_date__gte=timezone.now().date()).first()
         transaction.save()
         return response.Response(status=status.HTTP_204_NO_CONTENT)
 
@@ -266,7 +259,6 @@ class CartCompleteTransaction(rest_framework_views.APIView):
                 'Transaction cannot be completed unless the status is "Being shipped".'
             ))
         transaction.transaction_status = '005'
-        
         transaction.save()
         return response.Response(status=status.HTTP_204_NO_CONTENT)
 
@@ -309,6 +301,10 @@ class DonationCreate(rest_framework_views.APIView):
         serializer = self.get_serializer(data=request.data)
         serializer.is_valid(raise_exception=True)
         user = request.user
+        bank_account_transfer_destination = shortcuts.get_object_or_404(
+            models.BankAccountTransferDestination,
+            id=serializer.validated_data['bank_account_transfer_destination']
+        )
         program = shortcuts.get_object_or_404(
             models.Program,
             id=serializer.validated_data['program']
@@ -317,45 +313,15 @@ class DonationCreate(rest_framework_views.APIView):
             raise rest_framework_exceptions.PermissionDenied(_(
                 'This program is currently not accepting donations.'
             ))
-        program_donation = None
-        if serializer.validated_data['donation_type'] == 'CSH':
-            bank_account_transfer_destination = shortcuts.get_object_or_404(
-                models.BankAccountTransferDestination,
-                id=serializer.validated_data['bank_account_transfer_destination']
-            )
-            program_donation = models.ProgramDonation.objects.create(
-                user=user,
-                program=program,
-                donation_type='CSH',
-                amount=serializer.validated_data['amount'],
-                proof_of_bank_transfer=serializer.validated_data['proof_of_bank_transfer'],
-                user_bank_name=serializer.validated_data['user_bank_name'],
-                user_bank_account_name=serializer.validated_data['user_bank_account_name'],
-                bank_account_transfer_destination=bank_account_transfer_destination
-            )
-            
-        else:
-            if serializer.validated_data['delivery_method'] == 'DLV':
-                program_donation = models.ProgramDonation.objects.create(
-                user=user,
-                program=program,
-                donation_type='GDS',
-                goods_quantity=serializer.validated_data['goods_quantity'],
-                goods_description=serializer.validated_data['goods_description'],
-                delivery_method=serializer.validated_data['delivery_method'],
-                delivery_address=None
-            )
-            else:
-                program_donation = models.ProgramDonation.objects.create(
-                    user=user,
-                    program=program,
-                    donation_type='GDS',
-                    goods_quantity=serializer.validated_data['goods_quantity'],
-                    goods_description=serializer.validated_data['goods_description'],
-                    delivery_method=serializer.validated_data['delivery_method'],
-                    delivery_address=serializer.validated_data['delivery_address']
-                )
-        
+        program_donation = models.ProgramDonation.objects.create(
+            user=user,
+            program=program,
+            amount=serializer.validated_data['amount'],
+            proof_of_bank_transfer=serializer.validated_data['proof_of_bank_transfer'],
+            user_bank_name=serializer.validated_data['user_bank_name'],
+            user_bank_account_name=serializer.validated_data['user_bank_account_name'],
+            bank_account_transfer_destination=bank_account_transfer_destination
+        )
         return response.Response(
             {'program_donation': program_donation.id},
             status=status.HTTP_200_OK
@@ -386,10 +352,6 @@ class DonationReuploadProofOfBankTransfer(rest_framework_views.APIView):
             raise rest_framework_exceptions.PermissionDenied(_(
                 'Cannot reupload proof of bank transfer at this stage.'
             ))
-        if program_donation.donation_type != 'CSH':
-            raise rest_framework_exceptions.PermissionDenied(_(
-                'Cannot proof of bank transfer foor good donation.'
-            ))
         program_donation.amount = serializer.validated_data['amount']
         program_donation.proof_of_bank_transfer = (
             serializer.validated_data['proof_of_bank_transfer']
@@ -437,11 +399,10 @@ class ReportTransaction(ReportAPIView):
 
     def get_filename(self, query_params):
         filename = '{}.xlsx'.format(_( # pylint: disable=no-member
-            'Transaction Report from {date_from} to {date_to} for {batch_name}'
+            'Transaction Report from {date_from} to {date_to}'
         ).format(
             date_from=query_params.get('created_at_date_range_after', '_'),
-            date_to=query_params.get('created_at_date_range_before', str(timezone.now())[:10]),
-            batch_name=query_params.get('batch_name', '_')
+            date_to=query_params.get('created_at_date_range_before', str(timezone.now())[:10])
         ))
         return filename
 
@@ -705,6 +666,7 @@ class ProgramDetail(generics.RetrieveUpdateDestroyAPIView):
     queryset = models.Program.objects.all()
     serializer_class = api_serializers.ProgramSerializer
 
+
 class ProgramDonationList(generics.ListAPIView):
     filter_backends = [
         rest_framework.DjangoFilterBackend,
@@ -717,29 +679,7 @@ class ProgramDonationList(generics.ListAPIView):
     permission_classes = [rest_framework_permissions.IsAuthenticated]
     queryset = models.ProgramDonation.objects.all()
     schema = schemas.ProgramDonationListSchema()
-    search_fields = ['donation_number', 'user_full_name', 'program_name', 'donation_type']
-    serializer_class = api_serializers.ProgramDonationSerializer
-
-    def filter_queryset(self, queryset):
-        queryset = super().filter_queryset(queryset)
-        if not self.request.user.is_staff:
-            return queryset.filter(user=self.request.user)
-        return queryset
-
-
-class ProgramDonationListCSH(generics.ListAPIView):
-    filter_backends = [
-        rest_framework.DjangoFilterBackend,
-        rest_framework_filters.OrderingFilter,
-        rest_framework_filters.SearchFilter,
-    ]
-    filterset_class = api_filters.ProgramDonationFilter
-    ordering_fields = ['created_at', 'updated_at']
-    pagination_class = paginations.SmallResultsSetPagination
-    permission_classes = [rest_framework_permissions.IsAuthenticated]
-    queryset = models.ProgramDonation.objects.filter(donation_type='CSH')
-    schema = schemas.ProgramDonationListSchema()
-    search_fields = ['donation_number', 'user_full_name', 'program_name', 'donation_type']
+    search_fields = ['donation_number', 'user_full_name', 'program_name']
     serializer_class = api_serializers.ProgramDonationSerializer
 
     def filter_queryset(self, queryset):
@@ -748,26 +688,6 @@ class ProgramDonationListCSH(generics.ListAPIView):
             return queryset.filter(user=self.request.user)
         return queryset
 
-class ProgramDonationListGDS(generics.ListAPIView):
-    filter_backends = [
-        rest_framework.DjangoFilterBackend,
-        rest_framework_filters.OrderingFilter,
-        rest_framework_filters.SearchFilter,
-    ]
-    filterset_class = api_filters.ProgramDonationFilter
-    ordering_fields = ['created_at', 'updated_at']
-    pagination_class = paginations.SmallResultsSetPagination
-    permission_classes = [rest_framework_permissions.IsAuthenticated]
-    queryset = models.ProgramDonation.objects.filter(donation_type='GDS')
-    schema = schemas.ProgramDonationListSchema()
-    search_fields = ['donation_number', 'user_full_name', 'program_name', 'donation_type']
-    serializer_class = api_serializers.ProgramDonationSerializer
-
-    def filter_queryset(self, queryset):
-        queryset = super().filter_queryset(queryset)
-        if not self.request.user.is_staff:
-            return queryset.filter(user=self.request.user)
-        return queryset 
 
 class ProgramDonationDetail(generics.RetrieveUpdateAPIView):
     permission_classes = [
@@ -839,80 +759,3 @@ class ShipmentConfigDetail(generics.RetrieveUpdateAPIView):
     def get_object(self):
         obj = shortcuts.get_object_or_404(models.ShipmentConfig)
         return obj
-
-class BatchList(generics.ListCreateAPIView):
-    filter_backends = [
-        rest_framework.DjangoFilterBackend,
-        rest_framework_filters.OrderingFilter,
-        rest_framework_filters.SearchFilter,
-    ]
-    
-    filterset_class = api_filters.BatchFilter
-    ordering_fields = ['created_at', 'updated_at']
-    pagination_class = paginations.SmallResultsSetPagination
-    permission_classes = [rest_framework_permissions.IsAuthenticated]
-    queryset = models.Batch.objects.all()
-    schema = schemas.BatchListSchema()
-    search_fields = ['batch_name']
-    serializer_class = api_serializers.BatchSerializer
-
-    def post(self, request, _format=None):
-        serializer = self.get_serializer(data=request.data)
-        serializer.is_valid(raise_exception=True)
-        
-        if(serializer.validated_data['start_date']<serializer.validated_data['end_date']):
-            batch = models.Batch.objects.create(
-                batch_name=serializer.validated_data['batch_name'],
-                start_date=serializer.validated_data['start_date'],
-                end_date=serializer.validated_data['end_date'],
-                shipping_cost=serializer.validated_data['shipping_cost'],  
-            )
-        else:
-            raise rest_framework_exceptions.PermissionDenied(_(
-                'Start Date must be earlier than End Date.'
-            ))
-        return response.Response(
-            {'id': batch.id},
-            status=status.HTTP_201_CREATED
-        )
-
-    def filter_queryset(self, queryset):
-        queryset = super().filter_queryset(queryset)
-        if not self.request.user.is_staff:
-            return queryset.filter(user=self.request.user)
-        return queryset
-        
-class BatchDetail(generics.RetrieveUpdateDestroyAPIView):
-    permission_classes = [
-        api_permissions.IsAdminUserOrReadOnly,
-        rest_framework_permissions.IsAuthenticated,
-    ]
-    queryset = models.Batch.objects.all()
-    serializer_class = api_serializers.BatchSerializer
-
-class BatchCreate(rest_framework_views.APIView):
-    permission_classes = [rest_framework_permissions.IsAuthenticated]
-    serializer_class = api_serializers.BatchCreateSerializer
-
-    def get_serializer(self, *args, **kwargs):
-        return self.serializer_class(*args, **kwargs)
-
-    def post(self, request, _format=None):
-        serializer = self.get_serializer(data=request.data)
-        serializer.is_valid(raise_exception=True)
-        
-        if(serializer.validate_data['start_date']<serializer.validate_date['end_date']):
-            batch = models.Batch.objects.create(
-                batch_name=serializer.validated_data['batch_name'],
-                start_date=serializer.validated_data['start_date'],
-                end_date=serializer.validated_data['end_date'],
-                shipping_cost=serializer.validated_data['shipping_cost'],  
-            )
-        else:
-            raise rest_framework_exceptions.PermissionDenied(_(
-                'Start Date must be earlier than End Date.'
-            ))
-        return response.Response(
-            {'id': batch.id},
-            status=status.HTTP_201_CREATED
-        )
diff --git a/home_industry/settings/local.py b/home_industry/settings/local.py
index fe04e340..81f7d36c 100644
--- a/home_industry/settings/local.py
+++ b/home_industry/settings/local.py
@@ -11,7 +11,7 @@ SECRET_KEY = os.environ['SECRET_KEY']
 
 DEBUG = os.environ.get('DEBUG', True) != 'False'
 
-ALLOWED_HOSTS = ['127.0.0.1', 'localhost', '10.0.2.2']
+ALLOWED_HOSTS = ['127.0.0.1', 'localhost']
 
 # Application definition
 
diff --git a/manage.py b/manage.py
old mode 100644
new mode 100755
-- 
GitLab