diff --git a/bluebottle/funding_lipisha/admin.py b/bluebottle/funding_lipisha/admin.py index 3eb0c9bb6b..fe09d8c571 100644 --- a/bluebottle/funding_lipisha/admin.py +++ b/bluebottle/funding_lipisha/admin.py @@ -22,6 +22,7 @@ class LipishaPaymentProviderAdmin(PaymentProviderChildAdmin): class LipishaBankAccountAdmin(BankAccountChildAdmin): fields = ( 'mpesa_code', + 'payout_code', 'account_number', 'account_name', 'bank_name', diff --git a/bluebottle/funding_lipisha/effects.py b/bluebottle/funding_lipisha/effects.py new file mode 100644 index 0000000000..1369af8177 --- /dev/null +++ b/bluebottle/funding_lipisha/effects.py @@ -0,0 +1,31 @@ +from django.utils.translation import gettext as _ + +from bluebottle.fsm.effects import Effect +from bluebottle.funding_lipisha.utils import generate_payout_account, generate_mpesa_account + + +class GenerateLipishaAccountsEffect(Effect): + conditions = [] + title = _('Generate Lipisha accounts') + template = 'admin/generate_lipisha_accounts_effect.html' + + def post_save(self, **kwargs): + account = self.instance + if not self.instance.mpesa_code: + self.instance.mpesa_code = generate_mpesa_account( + name=account.account_name + ) + self.instance.save() + if not self.instance.payout_code: + self.instance.payout_code = generate_payout_account( + name=account.account_name, + number=account.account_number, + bank_name=account.bank_name, + bank_branch=account.branch_name, + bank_address=account.address, + swift_code=account.swift + ) + self.instance.save() + + def __str__(self): + return _('Generate Lipisha accounts to receive a MPESA code.') diff --git a/bluebottle/funding_lipisha/migrations/0009_auto_20220901_1328.py b/bluebottle/funding_lipisha/migrations/0009_auto_20220901_1328.py new file mode 100644 index 0000000000..12eb7ae89e --- /dev/null +++ b/bluebottle/funding_lipisha/migrations/0009_auto_20220901_1328.py @@ -0,0 +1,47 @@ +# Generated by Django 2.2.24 on 2022-09-01 11:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('funding_lipisha', '0008_lipishabankaccount_mpesa_code'), + ] + + operations = [ + migrations.AlterModelOptions( + name='lipishapayment', + options={'base_manager_name': 'objects'}, + ), + migrations.AddField( + model_name='lipishabankaccount', + name='payout_code', + field=models.CharField(blank=True, help_text='Generated by magic', max_length=50, null=True, unique=True, verbose_name='MPESA code'), + ), + migrations.AlterField( + model_name='lipishabankaccount', + name='mpesa_code', + field=models.CharField(blank=True, help_text='Generated by magic', max_length=50, null=True, unique=True, verbose_name='MPESA code'), + ), + migrations.AlterField( + model_name='lipishabankaccount', + name='swift', + field=models.CharField(blank=True, max_length=50, null=True, verbose_name='SWIFT/Routing Code'), + ), + migrations.AlterField( + model_name='lipishapayment', + name='method', + field=models.CharField(default='Paybill (M-Pesa)', max_length=30), + ), + migrations.AlterField( + model_name='lipishapaymentprovider', + name='paybill', + field=models.CharField(help_text='Find this at https://app.lypa.io/payment under `Business Number`', max_length=10, verbose_name='Business Number'), + ), + migrations.AlterField( + model_name='lipishapaymentprovider', + name='prefix', + field=models.CharField(default='goodup', max_length=100), + ), + ] diff --git a/bluebottle/funding_lipisha/models.py b/bluebottle/funding_lipisha/models.py index 452a2a872b..671578f4df 100644 --- a/bluebottle/funding_lipisha/models.py +++ b/bluebottle/funding_lipisha/models.py @@ -12,7 +12,10 @@ class LipishaPaymentProvider(PaymentProvider): api_key = models.CharField(max_length=100) api_signature = models.CharField(max_length=500) - prefix = models.CharField(max_length=100, default='goodup') + prefix = models.CharField( + max_length=100, default='goodup', + help_text=_('Use the Lipisha account name e.g. "opc"') + ) paybill = models.CharField( _('Business Number'), max_length=10, help_text='Find this at https://app.lypa.io/payment under `Business Number`') @@ -32,7 +35,8 @@ def payment_methods(self): def private_settings(self): return { 'api_key': self.api_key, - 'api_signature': self.api_signature + 'api_signature': self.api_signature, + 'prefix': self.prefix } class Meta(object): @@ -71,7 +75,12 @@ class LipishaBankAccount(BankAccount): mpesa_code = models.CharField( 'MPESA code', - help_text='Create a channel here: https://app.lypa.io/account and copy the generated `Number`.', + help_text='Generated by magic', + unique=True, max_length=50, blank=True, null=True) + + payout_code = models.CharField( + 'Lipisha payout code', + help_text='Generated by magic', unique=True, max_length=50, blank=True, null=True) def save(self, *args, **kwargs): diff --git a/bluebottle/funding_lipisha/templates/admin/generate_lipisha_accounts_effect.html b/bluebottle/funding_lipisha/templates/admin/generate_lipisha_accounts_effect.html new file mode 100644 index 0000000000..f29876f33f --- /dev/null +++ b/bluebottle/funding_lipisha/templates/admin/generate_lipisha_accounts_effect.html @@ -0,0 +1,12 @@ +{% load i18n %} +

{% trans "Generate Lipisha Accounts" %}

+ +

+ {% trans "Generate Lipisha accounts for" %} + "{{effects.0.instance}}" + {% if effects|length > 1 %} + {% blocktrans with extra=effects|length|add:"-1" %} + and {{ extra }} other campaigns + {% endblocktrans %} + {% endif %} +

diff --git a/bluebottle/funding_lipisha/tests/test_triggers.py b/bluebottle/funding_lipisha/tests/test_triggers.py new file mode 100644 index 0000000000..90bc0fae69 --- /dev/null +++ b/bluebottle/funding_lipisha/tests/test_triggers.py @@ -0,0 +1,17 @@ +from bluebottle.funding_lipisha.effects import GenerateLipishaAccountsEffect +from bluebottle.funding_lipisha.tests.factories import LipishaBankAccountFactory +from bluebottle.test.utils import TriggerTestCase + + +class LipishaAccountTriggerTests(TriggerTestCase): + + factory = LipishaBankAccountFactory + defaults = {} + + def test_verify(self): + self.create() + self.model.states.verify() + + with self.execute(): + self.assertEqual(self.model.status, 'verified') + self.assertEffect(GenerateLipishaAccountsEffect) diff --git a/bluebottle/funding_lipisha/triggers.py b/bluebottle/funding_lipisha/triggers.py new file mode 100644 index 0000000000..1564538076 --- /dev/null +++ b/bluebottle/funding_lipisha/triggers.py @@ -0,0 +1,20 @@ +from bluebottle.activities.triggers import ActivityTriggers +from bluebottle.fsm.triggers import ( + TransitionTrigger, register +) +from bluebottle.funding_lipisha.effects import GenerateLipishaAccountsEffect +from bluebottle.funding_lipisha.models import LipishaBankAccount +from bluebottle.funding_lipisha.states import LipishaBankAccountStateMachine + + +@register(LipishaBankAccount) +class LipishaBankAccountTriggers(ActivityTriggers): + triggers = ActivityTriggers.triggers + [ + + TransitionTrigger( + LipishaBankAccountStateMachine.verify, + effects=[ + GenerateLipishaAccountsEffect + ] + ), + ] diff --git a/bluebottle/funding_lipisha/utils.py b/bluebottle/funding_lipisha/utils.py index 97f4e6b1cb..f270f60057 100644 --- a/bluebottle/funding_lipisha/utils.py +++ b/bluebottle/funding_lipisha/utils.py @@ -248,3 +248,32 @@ def acknowledge_payment(data): pass payment.save() return generate_success_response(payment) + + +def generate_payout_account( + name, number, bank_name, bank_branch, bank_address, swift_code +): + credentials = get_credentials() + client = init_client() + data = client.create_withdrawal_account( + transaction_account_type="1", + transaction_account_name=name, + transaction_account_number=number, + transaction_account_bank_name=bank_name, + transaction_account_bank_branch=bank_branch, + transaction_account_bank_address=bank_address, + transaction_account_swift_code=swift_code, + transaction_account_manager=credentials['prefix'] + ) + return data['content']['transaction_account_number'] + + +def generate_mpesa_account(name): + credentials = get_credentials() + client = init_client() + data = client.create_payment_account( + transaction_account_type=1, + transaction_account_name=name, + transaction_account_manager=credentials['prefix'] + ) + return data['content']['transaction_account_number'] diff --git a/setup.py b/setup.py index 9741925420..72f718c0b0 100755 --- a/setup.py +++ b/setup.py @@ -85,7 +85,7 @@ def read_file(name): 'html5lib==1.0b10', 'icalendar==4.0.4', 'influxdb==4.1.1', - 'lipisha==0.2.4', + 'lipisha==0.3.0', 'lxml==4.6.3', 'micawber==0.5.2', 'mixpanel==4.3.2',