diff --git a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json index c80f75d1289f6275688761318d63c6a075ada96c..9d1abb6c3e623ba1e5b76d438c89dd05d67b4ad9 100644 --- a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json +++ b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.json @@ -125,7 +125,59 @@ "name": "Mode of Payment", "naming_rule": "By fieldname", "owner": "Administrator", - "permissions": [], + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "select": 1, + "share": 1, + "write": 1 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Sales Master Manager", + "select": 1, + "share": 1, + "write": 1 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts Manager", + "select": 1, + "share": 1, + "write": 1 + }, + { + "create": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Accounts User", + "select": 1, + "share": 1, + "write": 1 + } + ], "quick_entry": 1, "show_name_in_global_search": 1, "show_preview_popup": 1, diff --git a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py index d4d9060f12054faff83f41300ab0fd18f97f343d..25038ac6c6b91fcd5f6fc1296ad66a995a800bf8 100644 --- a/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py +++ b/erpnext/accounts/doctype/mode_of_payment/mode_of_payment.py @@ -8,6 +8,30 @@ from frappe.model.document import Document class ModeofPayment(Document): + # begin: auto-generated types + # This code is auto-generated. Do not modify anything in this block. + + from typing import TYPE_CHECKING + + if TYPE_CHECKING: + from frappe.types import DF + + from erpnext.accounts.doctype.mode_of_payment_account.mode_of_payment_account import ( + ModeofPaymentAccount, + ) + + accounts: DF.Table[ModeofPaymentAccount] + cost_center: DF.Link | None + enabled: DF.Check + fee_account: DF.Link | None + icon: DF.Literal["Credit Card", "Wire Transfer", "Bank Draft", "Cash", "Cheque", "Other"] + mode_of_payment: DF.Data + payment_gateway: DF.Link | None + portal_description: DF.MarkdownEditor | None + tax_account: DF.Link | None + type: DF.Literal["Cash", "Bank"] + # end: auto-generated types + def validate(self): self.validate_accounts() self.validate_repeating_companies() diff --git a/erpnext/accounts/page/bank_reconciliation/gocardless_reconciliation.py b/erpnext/accounts/page/bank_reconciliation/gocardless_reconciliation.py index 148f8e6af02d282764a7e18e4b7fde8d3c3ba40e..1df9868067fd5328ce982d520e30ae44193cd83e 100644 --- a/erpnext/accounts/page/bank_reconciliation/gocardless_reconciliation.py +++ b/erpnext/accounts/page/bank_reconciliation/gocardless_reconciliation.py @@ -5,9 +5,9 @@ import re import frappe +from payments.payment_gateways.doctype.gocardless_settings.api import GoCardlessPayouts from erpnext.accounts.page.bank_reconciliation.bank_reconciliation import BankReconciliation -from erpnext.erpnext_integrations.doctype.gocardless_settings.api import GoCardlessPayouts def reconcile_gocardless_payouts(bank_transactions): diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/__init__.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/__init__.py deleted file mode 100644 index 8445fcc49b6890586f17c0a9e8f1d2f4c4f80bf1..0000000000000000000000000000000000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/__init__.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright (c) 2018, Frappe Technologies and contributors -# For license information, please see license.txt - - -import json -from urllib.parse import parse_qs - -import frappe -from frappe import _ -from gocardless_pro import webhooks as gocardless_webhooks -from gocardless_pro.errors import InvalidSignatureError - - -@frappe.whitelist(allow_guest=True) -def webhooks(): - r = frappe.request - if not r: - return - - account, events = get_events(r) - for event in events: - try: - doc = create_new_integration_log(event, account) - - frappe.enqueue( - method="erpnext.erpnext_integrations.doctype.gocardless_settings.gocardless_settings.handle_webhooks", - queue="long", - timeout=600, - is_async=True, - **{"doctype": "Integration Request", "docname": doc.name} - ) - except Exception: - frappe.log_error(_("GoCardless webhooks processing error")) - - frappe.response.message = "Webhook received and event type handled" - frappe.response.http_status_code = 200 - - -def get_events(request): - account, secret = get_api_key(request) - received_signature = frappe.get_request_header("Webhook-Signature") - payload = request.get_data() - try: - data = gocardless_webhooks.parse(payload, secret, received_signature) - return account, data - - except InvalidSignatureError: - frappe.log_error(_("GoCardless webhook error")) - except Exception: - frappe.log_error(_("GoCardless webhook error")) - - -def get_api_key(request): - account = None - if request.query_string: - parsed_qs = parse_qs(frappe.safe_decode(request.query_string)) - account = parsed_qs.get("account") - - if isinstance(account, list): - account = account[0] - - if account: - return account, frappe.db.get_value("GoCardless Settings", account, "webhooks_secret") - else: - gocardless_accounts = frappe.get_all("GoCardless Settings") - if len(gocardless_accounts) > 1: - frappe.log_error( - message=_("Please define your GoCardless account in the webhook URL's query string"), - title=_("GoCardless webhook error"), - ) - else: - return gocardless_accounts[0].get("name"), frappe.db.get_value( - "GoCardless Settings", gocardless_accounts[0].get("name"), "webhooks_secret" - ) - - -def create_new_integration_log(event, account): - integration_request = frappe.get_doc( - { - "doctype": "Integration Request", - "request_description": "Webhook", - "integration_request_service": "GoCardless", - "service_document": event.attributes.get("resource_type"), - "service_status": event.attributes.get("action"), - "service_id": event.attributes.get("id"), - "data": json.dumps(event.attributes, indent=4), - "payment_gateway_controller": account, - } - ) - - integration_request.flags._name = event.attributes.get("id") - - integration_request.insert(ignore_permissions=True) - frappe.db.commit() - - return integration_request diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/__init__.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/api/__init__.py deleted file mode 100644 index 1d6a8588dc78d43e2fbe9d9831f72a2c297a54c2..0000000000000000000000000000000000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from .customers import GoCardlessCustomers -from .events import GoCardlessEvents -from .mandates import GoCardlessMandates -from .payments import GoCardlessPayments -from .payout_items import GoCardlessPayoutItems -from .payouts import GoCardlessPayouts diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/customers.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/api/customers.py deleted file mode 100644 index c84596c89357d1941a446c68aaeec9e771b55db5..0000000000000000000000000000000000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/customers.py +++ /dev/null @@ -1,46 +0,0 @@ -import frappe - - -class GoCardlessCustomers: - def __init__(self, gateway): - self.gateway = gateway - self.client = self.gateway.client - - # Restricted to GoCardless Pro - def create(self, **kwargs): - return self.client.customers.create(params=kwargs) - - def get(self, id): - return self.client.customers.get(id) - - def update(self, id, **kwargs): - return self.client.customers.update(id, params=kwargs) - - def remove(self, id): - return self.client.customers.remove( - id, - ) - - def get_list(self, **kwargs): - return self.client.customers.list(params=kwargs) - - def register(self, gocardless_id, customer): - try: - if frappe.db.exists("Integration References", dict(customer=customer)): - doc = frappe.get_doc("Integration References", dict(customer=customer)) - doc.gocardless_customer_id = gocardless_id - doc.gocardless_settings = self.gateway.name - doc.save(ignore_permissions=True) - - else: - frappe.get_doc( - { - "doctype": "Integration References", - "customer": customer, - "gocardless_customer_id": gocardless_id, - "gocardless_settings": self.gateway.name, - } - ).insert(ignore_permissions=True) - frappe.db.commit() - except Exception as e: - frappe.log_error(e, "GoCardless Customer ID Registration Error") diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/events.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/api/events.py deleted file mode 100644 index 871bdcb85534e6350e7f961f90d95f0e224e4562..0000000000000000000000000000000000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/events.py +++ /dev/null @@ -1,13 +0,0 @@ -import frappe - - -class GoCardlessEvents: - def __init__(self, gateway): - self.gateway = gateway - self.client = self.gateway.client - - def get(self, id): - return self.client.events.get(id) - - def get_list(self, **kwargs): - return self.client.events.list(params=kwargs) diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/mandates.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/api/mandates.py deleted file mode 100644 index c32303cded20408344d82bd6f69dca8d7ab6eb09..0000000000000000000000000000000000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/mandates.py +++ /dev/null @@ -1,39 +0,0 @@ -import frappe -from frappe.utils import nowdate - - -class GoCardlessMandates: - def __init__(self, gateway): - self.gateway = gateway - self.client = self.gateway.client - - # Restricted to GoCardless Pro - def create(self, **kwargs): - return self.client.mandates.create(params=kwargs) - - def get(self, id): - return self.client.mandates.get(id) - - def update(self, id, **kwargs): - return self.client.mandates.update(id, params=kwargs) - - def remove(self, id): - return self.client.mandates.remove( - id, - ) - - def get_list(self, **kwargs): - return self.client.mandates.list(params=kwargs) - - def register(self, id, customer): - if not frappe.db.exists("Sepa Mandate", id): - frappe.get_doc( - { - "doctype": "Sepa Mandate", - "mandate": id, - "customer": customer, - "registered_on_gocardless": 1, - "creation_date": nowdate(), - } - ).insert(ignore_permissions=True) - frappe.db.commit() diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/payments.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/api/payments.py deleted file mode 100644 index 4c729b25a49236f62178e751da083723286fa23b..0000000000000000000000000000000000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/payments.py +++ /dev/null @@ -1,35 +0,0 @@ -from payments.payment_gateways.doctype.stripe_settings.idempotency import ( - IdempotencyKey, - handle_idempotency, -) - - -class GoCardlessPayments: - def __init__(self, gateway, reference=None): - self.gateway = gateway - self.client = self.gateway.client - self.reference = reference - - @handle_idempotency - def create(self, **kwargs): - return self.client.payments.create( - params=kwargs, - headers={ - "Idempotency-Key": IdempotencyKey("payments", "create", self.reference).get(), - }, - ) - - def get(self, id): - return self.client.payments.get(id) - - def get_list(self, params): - return self.client.payments.list(params=params) - - def update(self, id, **kwargs): - return self.client.payments.update(id, params=kwargs) - - def cancel(self, id, **kwargs): - return self.client.payments.cancel(id, params=kwargs) - - def retry(self, id, **kwargs): - return self.client.payments.retry(id, params=kwargs) diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/payout_items.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/api/payout_items.py deleted file mode 100644 index 843e1f20492b2644464b226be9b0d7eff8f498ec..0000000000000000000000000000000000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/payout_items.py +++ /dev/null @@ -1,7 +0,0 @@ -class GoCardlessPayoutItems: - def __init__(self, gateway): - self.gateway = gateway - self.client = self.gateway.client - - def get_list(self, payout, **kwargs): - return self.client.payout_items.list(params=dict({"payout": payout}, **kwargs)) diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/payouts.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/api/payouts.py deleted file mode 100644 index 77b71b67366d542478edd566dfbcfcf8c450a589..0000000000000000000000000000000000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/api/payouts.py +++ /dev/null @@ -1,10 +0,0 @@ -class GoCardlessPayouts: - def __init__(self, gateway): - self.gateway = gateway - self.client = self.gateway.client - - def get(self, id): - return self.client.payouts.get(id) - - def get_list(self, **kwargs): - return self.client.payouts.list(params=kwargs) diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.js b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.js deleted file mode 100644 index 241129719b826dda4bdffc006d06d8c14bee47b9..0000000000000000000000000000000000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2018, Frappe Technologies and contributors -// For license information, please see license.txt - -frappe.ui.form.on('GoCardless Settings', { - refresh: function(frm) { - erpnext.utils.check_payments_app(); - } -}); diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.json b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.json deleted file mode 100644 index 34d310ac085d62a61a4c6ae92af52ed90f5078e8..0000000000000000000000000000000000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "actions": [], - "autoname": "field:gateway_name", - "creation": "2018-02-06 16:11:10.028249", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "gateway_name", - "access_token", - "webhooks_secret", - "use_sandbox", - "settings_section", - "bank_account" - ], - "fields": [ - { - "fieldname": "gateway_name", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Payment Gateway Name", - "reqd": 1, - "unique": 1 - }, - { - "fieldname": "access_token", - "fieldtype": "Password", - "in_list_view": 1, - "label": "Access Token", - "reqd": 1 - }, - { - "fieldname": "webhooks_secret", - "fieldtype": "Data", - "label": "Webhooks Secret" - }, - { - "default": "0", - "fieldname": "use_sandbox", - "fieldtype": "Check", - "label": "Use Sandbox" - }, - { - "fieldname": "settings_section", - "fieldtype": "Section Break", - "label": "Settings" - }, - { - "fieldname": "bank_account", - "fieldtype": "Link", - "label": "Bank Account", - "options": "Bank Account" - } - ], - "links": [], - "modified": "2022-02-12 14:18:47.209114", - "modified_by": "Administrator", - "module": "ERPNext Integrations", - "name": "GoCardless Settings", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py deleted file mode 100644 index 629aece27f21fb6fd5d9f356a8bf816f8d4f4bc7..0000000000000000000000000000000000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings.py +++ /dev/null @@ -1,212 +0,0 @@ -# Copyright (c) 2023, Dokos SAS and contributors -# For license information, please see license.txt - - -from urllib.parse import urlencode - -import frappe -import gocardless_pro -from frappe import _ -from frappe.utils import call_hook_method, cint, flt, get_url -from gocardless_pro import errors -from payments.utils.utils import PaymentGatewayController - -from erpnext.erpnext_integrations.doctype.gocardless_settings.api import ( - GoCardlessCustomers, - GoCardlessMandates, - GoCardlessPayments, - GoCardlessPayoutItems, - GoCardlessPayouts, -) -from erpnext.erpnext_integrations.doctype.gocardless_settings.webhook_events import ( - GoCardlessWebhookHandler, -) -from erpnext.utilities import payment_app_import_guard - - -class GoCardlessSettings(PaymentGatewayController): - supported_currencies = ["AUD", "CAD", "DKK", "EUR", "GBP", "NZD", "SEK", "USD"] - - def __init__(self, *args, **kwargs): - super(GoCardlessSettings, self).__init__(*args, **kwargs) - if not self.is_new(): - self.initialize_client() - - def validate(self): - self.initialize_client() - - def initialize_client(self): - self.environment = self.get_environment() - try: - self.client = gocardless_pro.Client( - access_token=self.get_password(fieldname="access_token", raise_exception=False), - environment=self.environment, - ) - return self.client - except Exception as e: - frappe.throw(str(e)) - - def on_update(self): - with payment_app_import_guard(): - from payments.utils import create_payment_gateway - - create_payment_gateway( - "GoCardless-" + self.gateway_name, settings="GoCardLess Settings", controller=self.gateway_name - ) - call_hook_method("payment_gateway_enabled", gateway="GoCardless-" + self.gateway_name) - - def immediate_payment_processing( - self, reference, customer, amount, currency, description, metadata - ): - try: - processed_data = dict( - amount=round(flt(amount) * 100.0), - currency=currency, - description=description, - reference=reference, - links={}, - metadata=metadata, - ) - - valid_mandate = self.check_mandate_validity(customer) - if valid_mandate.get("mandate"): - processed_data["links"] = valid_mandate - - return getattr(GoCardlessPayments(self, reference).create(**processed_data), "id", None) - else: - frappe.throw(_("This customer has no valid mandate")) - - except Exception: - self.log_error( - _("GoCardless direct processing failed for {0}".format(reference)), - ) - - def check_mandate_validity(self, customer=None): - if customer and frappe.db.exists( - "Sepa Mandate", dict(customer=customer, status=["not in", ["Cancelled", "Expired", "Failed"]]) - ): - registered_mandate = frappe.db.get_value( - "Sepa Mandate", - dict(customer=customer, status=["not in", ["Cancelled", "Expired", "Failed"]]), - "mandate", - ) - - try: - mandate = GoCardlessMandates(self).get(registered_mandate) - - if ( - mandate.status == "pending_customer_approval" - or mandate.status == "pending_submission" - or mandate.status == "submitted" - or mandate.status == "active" - ): - return {"mandate": registered_mandate} - except errors.InvalidApiUsageError: - pass - return {} - - def get_environment(self): - return "sandbox" if self.use_sandbox else "live" - - def validate_transaction_currency(self, currency): - if currency not in self.supported_currencies: - frappe.throw( - _( - "Please select another payment method. GoCardless does not support transactions in currency '{0}'" - ).format(currency) - ) - - def get_payment_url(self, **kwargs): - return get_url("./integrations/gocardless_checkout?{0}".format(urlencode(kwargs))) - - def handle_redirect_flow(self, redirect_flow, reference_document): - customer = reference_document.get("customer") or reference_document.get_customer() - if not customer: - return - - GoCardlessMandates(self).register(redirect_flow.links.mandate, customer) - - GoCardlessCustomers(self).register(redirect_flow.links.customer, customer) - - payment = GoCardlessPayments(self, reference_document.name).create( - amount=cint((reference_document.get("grand_total") or reference_document.get("amount")) * 100), - currency=reference_document.get("currency"), - description=reference_document.get("subject") or reference_document.get("description"), - reference=reference_document.name, - links={"mandate": redirect_flow.links.mandate}, - metadata={ - "reference_doctype": reference_document.doctype, - "reference_name": reference_document.name, - }, - ) - - return getattr(payment, "id") - - def get_transaction_fees(self, payments): - gc_payments = GoCardlessPayments(self).get(payments) - gc_payment_links = getattr(gc_payments, "links", {}) - gc_payout = getattr(gc_payment_links, "payout") - - if not gc_payout: - frappe.throw(_("This payment has not been paid out yet")) - - payout_items = GoCardlessPayoutItems(self).get_list(gc_payout) - - tax_amount = self.get_tax_amount(payout_items.records, gc_payments.id) - fees = frappe._dict( - base_amount=self.get_base_amount(payout_items.records, gc_payments.id), - fee_amount=self.get_fee_amount(payout_items.records, gc_payments.id) - tax_amount, - tax_amount=tax_amount, - exchange_rate=self.get_exchange_rate(GoCardlessPayouts(self).get(gc_payout)), - ) - - return fees - - @staticmethod - def get_base_amount(payout_items, payments): - paid_amount = sum( - [ - flt(record.amount) - for record in payout_items - if (record.type == "payment_paid_out" and record.links.payment == payments) - ] - ) - return paid_amount / 100 - - @staticmethod - def get_fee_amount(payout_items, payments): - fee_amount = sum( - [ - flt(record.amount) - for record in payout_items - if ( - (record.type == "gocardless_fee" or record.type == "app_fee") - and record.links.payment == payments - ) - ] - ) - return abs(fee_amount) / 100 - - @staticmethod - def get_tax_amount(payout_items, payments): - taxes = [] - for x in payout_items: - if (x.type == "gocardless_fee" or x.type == "app_fee") and x.links.payment == payments: - taxes.extend(x.taxes) - - return abs(sum([flt(x.get("amount")) for x in taxes])) / 100 - - @staticmethod - def get_exchange_rate(payout): - return flt(getattr(payout.fx, "exchange_rate", 1) or 1) - - -def handle_webhooks(**kwargs): - integration_request = frappe.get_doc(kwargs.get("doctype"), kwargs.get("docname")) - - if integration_request.service_document in ["mandates", "payments"]: - GoCardlessWebhookHandler(**kwargs) - else: - integration_request.handle_failure( - {"message": _("This type of event is not handled")}, "Not Handled" - ) diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings_dashboard.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings_dashboard.py deleted file mode 100644 index 922a8b6fe114b358d1a0ce6ba678f6cfbb48c1a6..0000000000000000000000000000000000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/gocardless_settings_dashboard.py +++ /dev/null @@ -1,8 +0,0 @@ -from frappe import _ - - -def get_data(): - return { - "fieldname": "gateway_controller", - "transactions": [{"label": _("Payment Gateways"), "items": ["Payment Gateway"]}], - } diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.py deleted file mode 100644 index 505d2848d5d8451052fcbff2b8fe5b8d4dbb2671..0000000000000000000000000000000000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/test_gocardless_settings.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2018, Frappe Technologies and Contributors -# See license.txt - - -import unittest - - -class TestGoCardlessSettings(unittest.TestCase): - pass diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/webhook_events/__init__.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/webhook_events/__init__.py deleted file mode 100644 index 0bb84056ace89a6dd7826862ccde1b8e670dcefc..0000000000000000000000000000000000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/webhook_events/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .gocardless import GoCardlessWebhookHandler \ No newline at end of file diff --git a/erpnext/erpnext_integrations/doctype/gocardless_settings/webhook_events/gocardless.py b/erpnext/erpnext_integrations/doctype/gocardless_settings/webhook_events/gocardless.py deleted file mode 100644 index de564e2d38a472dbdf399f80a179948f8fec54ba..0000000000000000000000000000000000000000 --- a/erpnext/erpnext_integrations/doctype/gocardless_settings/webhook_events/gocardless.py +++ /dev/null @@ -1,156 +0,0 @@ -import json - -import frappe -from frappe import _ - -from erpnext.erpnext_integrations.doctype.gocardless_settings.api import ( - GoCardlessMandates, - GoCardlessPayments, -) - -MANDATES_STATUS = { - "customer_approval_granted": "Pending Customer Approval", - "customer_approval_skipped": "Pending Submission", - "active": "Active", - "cancelled": "Cancelled", - "failed": "Failed", - "transferred": "Submitted", - "expired": "Expired", - "submitted": "Submitted", - "resubmission_requested": "Pending Submission", - "reinstated": "Active", - "replaced": "Cancelled", - "created": "Pending Submission", -} - -PAYMENTS_STATUS = { - "created": "Pending", - "submitted": "Pending", - "confirmed": "Paid", - "cancelled": "Failed", - "failed": "Failed", - "paid_out": "Paid", -} - - -class GoCardlessWebhookHandler: - def __init__(self, **kwargs): - self.integration_request = frappe.get_doc(kwargs.get("doctype"), kwargs.get("docname")) - self.integration_request.db_set("error", None) - self.data = json.loads(self.integration_request.get("data")) - self.payment = self.data.get("links", {}).get("payment") - self.metadata = {} - self.gocardless_settings = frappe.get_doc( - "GoCardless Settings", self.integration_request.payment_gateway_controller - ) - - if self.integration_request.service_document == "payments": - self.get_reference_documents() - - self.integration_request.load_from_db() - self.handle_webhook() - - def get_reference_documents(self): - gc_payment = GoCardlessPayments(self.gocardless_settings).get(self.payment) - self.metadata = getattr(gc_payment, "metadata", {}) - - for k in ("reference_doctype", "reference_docname", "reference_name"): - if k in self.metadata: - key = "reference_docname" if k == "reference_name" else k - self.integration_request.db_set(key, self.metadata[k]) - - # For compatibility - if "payment_request" in self.metadata: - self.integration_request.db_set("reference_doctype", "Payment Request") - self.integration_request.db_set("reference_docname", self.metadata["payment_request"]) - - def handle_webhook(self): - action = self.data.get("action") - service = self.integration_request.service_document - - if service == "payments": - self.handle_payments(action) - - elif service == "mandates": - self.handle_mandates(action) - - def handle_payments(self, action): - if action not in PAYMENTS_STATUS: - return self.integration_request.handle_failure( - response={"message": _("This type of event is not handled")}, status="Not Handled" - ) - - elif not ( - self.integration_request.reference_doctype and self.integration_request.reference_docname - ): - return self.integration_request.handle_failure( - response={"message": _("This event contains not metadata")}, status="Failed" - ) - - elif not frappe.db.exists( - self.integration_request.reference_doctype, self.integration_request.reference_docname - ): - return self.integration_request.handle_failure( - response={"message": _("The reference document does not exist")}, status="Failed" - ) - - try: - reference_document = frappe.get_doc( - self.integration_request.reference_doctype, self.integration_request.reference_docname - ) - response = reference_document.run_method( - "on_payment_authorized", status=PAYMENTS_STATUS[action], reference_no=self.payment - ) - - self.integration_request.handle_success(response={"message": response}) - - except Exception: - self.integration_request.handle_failure( - response={"message": frappe.get_traceback()}, status="Failed" - ) - - def handle_mandates(self, action): - if action not in MANDATES_STATUS: - return self.integration_request.handle_failure( - response={"message": _("This type of event is not handled")}, status="Not Handled" - ) - - try: - response = self.change_mandate_status() - self.integration_request.handle_success(response={"message": response}) - - except Exception: - self.integration_request.handle_failure( - response={"message": frappe.get_traceback()}, status="Failed" - ) - - def change_mandate_status(self): - mandate = self.data.get("links", {}).get("mandate") - if not frappe.db.exists("Sepa Mandate", mandate): - self.create_mandate(mandate) - - sepa_mandate = self.set_mandate_status(mandate, MANDATES_STATUS.get(self.data.get("action"))) - - self.integration_request.db_set("reference_doctype", "Sepa Mandate") - self.integration_request.db_set("reference_docname", sepa_mandate) - - return _("Mandate updated successfully") - - def create_mandate(self, mandate): - gc_mandate = GoCardlessMandates(self.gocardless_settings).get(mandate) or {} - gocardless_customer = gc_mandate.links.customer - customer = frappe.db.get_value( - "Integration References", {"gocardless_customer_id": gocardless_customer}, ["customer"] - ) - - if customer: - GoCardlessMandates(self.gocardless_settings).register(mandate, customer) - - def set_mandate_status(self, mandate, status): - doc = frappe.get_doc("Sepa Mandate", mandate) - if doc.status != status: - doc.status = status - doc.flags.ignore_permissions = True - doc.save() - - return doc.name diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py index b2e2df5812ef5135e109b41f93af53178c3a4ff8..4ad0fcce59150771605eeca73653af0b7f5553e2 100644 --- a/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py +++ b/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py @@ -43,40 +43,6 @@ class TestPlaidSettings(unittest.TestCase): add_account_subtype("loan") self.assertEqual(frappe.get_doc("Bank Account Subtype", "loan").name, "loan") - def test_default_bank_account(self): - if not frappe.db.exists("Bank", "Citi"): - frappe.get_doc({"doctype": "Bank", "bank_name": "Citi"}).insert() - - bank_accounts = { - "account": { - "subtype": "checking", - "mask": "0000", - "type": "depository", - "id": "6GbM6RRQgdfy3lAqGz4JUnpmR948WZFg8DjQK", - "name": "Plaid Checking", - }, - "account_id": "6GbM6RRQgdfy3lAqGz4JUnpmR948WZFg8DjQK", - "link_session_id": "db673d75-61aa-442a-864f-9b3f174f3725", - "accounts": [ - { - "type": "depository", - "subtype": "checking", - "mask": "0000", - "id": "6GbM6RRQgdfy3lAqGz4JUnpmR948WZFg8DjQK", - "name": "Plaid Checking", - } - ], - "institution": {"institution_id": "ins_6", "name": "Citi"}, - } - - bank = json.dumps(frappe.get_doc("Bank", "Citi").as_dict(), default=json_handler) - company = frappe.db.get_single_value("Global Defaults", "default_company") - frappe.db.set_value("Company", company, "default_bank_account", None) - - self.assertRaises( - frappe.ValidationError, add_bank_accounts, response=bank_accounts, bank=bank, company=company - ) - def test_new_transaction(self): if not frappe.db.exists("Bank", "Citi"): frappe.get_doc({"doctype": "Bank", "bank_name": "Citi"}).insert() diff --git a/erpnext/erpnext_integrations/utils.py b/erpnext/erpnext_integrations/utils.py index 5a03d3c8d62a4879940642ea0fd7d225e28031d3..f72b47250b602bbf4ca65d4cea78fcc3439a5de5 100644 --- a/erpnext/erpnext_integrations/utils.py +++ b/erpnext/erpnext_integrations/utils.py @@ -6,8 +6,6 @@ from urllib.parse import urlparse import frappe from frappe import _ -from erpnext import get_default_company - def validate_webhooks_request(doctype, hmac_key, secret_key="secret"): def innerfn(fn): @@ -45,32 +43,3 @@ def get_webhook_address(connector_name, method, exclude_uri=False, force_https=F server_url = f"{scheme}://{netloc}/api/method/{endpoint}" return server_url - - -def create_mode_of_payment(gateway, payment_type="General"): - payment_gateway_account = frappe.db.get_value( - "Payment Gateway Account", {"payment_gateway": gateway}, ["payment_account"] - ) - - mode_of_payment = frappe.db.exists("Mode of Payment", gateway) - if not mode_of_payment and payment_gateway_account: - mode_of_payment = frappe.get_doc( - { - "doctype": "Mode of Payment", - "mode_of_payment": gateway, - "enabled": 1, - "type": payment_type, - "accounts": [ - { - "doctype": "Mode of Payment Account", - "company": get_default_company(), - "default_account": payment_gateway_account, - } - ], - } - ) - mode_of_payment.insert(ignore_permissions=True) - - return mode_of_payment - elif mode_of_payment: - return frappe.get_doc("Mode of Payment", mode_of_payment) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 10f17fc0ca381419dc14fc3a717cebd593bfbfd5..320f9e4fd52bb244d7843a185d062a302881ab91 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -351,6 +351,7 @@ execute:frappe.db.set_single_value('Selling Settings', 'allow_negative_rates_for erpnext.patches.v15_0.correct_asset_value_if_je_with_workflow erpnext.patches.v15_0.delete_woocommerce_settings_doctype erpnext.patches.v14_0.migrate_deferred_accounts_to_item_defaults +erpnext.patches.v15_0.delete_payment_gateway_doctypes erpnext.patches.v14_0.create_accounting_dimensions_in_sales_order_item # @dokos @@ -373,5 +374,6 @@ execute:frappe.delete_doc_if_exists("DocType", "Portal Payment Gateways") execute:frappe.delete_doc_if_exists("DocType", "Subscription Event") # @dokos + # below migration patch should always run last erpnext.patches.v14_0.migrate_gl_to_payment_ledger diff --git a/erpnext/patches/v15_0/delete_payment_gateway_doctypes.py b/erpnext/patches/v15_0/delete_payment_gateway_doctypes.py new file mode 100644 index 0000000000000000000000000000000000000000..959b065780338be25ed5d5d32cd110b887fa06b4 --- /dev/null +++ b/erpnext/patches/v15_0/delete_payment_gateway_doctypes.py @@ -0,0 +1,6 @@ +import frappe + + +def execute(): + for dt in ("GoCardless Settings", "GoCardless Mandate", "Mpesa Settings"): + frappe.delete_doc("DocType", dt, ignore_missing=True) diff --git a/erpnext/templates/pages/integrations/__init__.py b/erpnext/templates/pages/integrations/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/erpnext/templates/pages/integrations/gocardless_checkout.html b/erpnext/templates/pages/integrations/gocardless_checkout.html deleted file mode 100644 index 3b855a45a7b91f0f2ecf4855883c40a142a60a52..0000000000000000000000000000000000000000 --- a/erpnext/templates/pages/integrations/gocardless_checkout.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "templates/web.html" %} - -{% block title %} Payment {% endblock %} - -{%- block header -%}{% endblock %} - -{%- block page_content -%} -
- {{ _("Loading Payment System") }} -
-- {{ _("Payment Confirmation") }} -
-