Пример #1
0
    def find_by_corp_type_and_filing_type(  # pylint: disable=too-many-arguments
        cls,
        corp_type: str,
        filing_type_code: str,
        valid_date: date,
        jurisdiction: str,
        priority: bool,
    ):
        """Calculate fees for the filing by using the arguments."""
        current_app.logger.debug('<get_fees_by_corp_type_and_filing_type')
        if not corp_type and not filing_type_code:
            raise BusinessException(Error.PAY001)
        if jurisdiction or priority:
            current_app.logger.warn(
                'Not using Jurisdiction and priority now!!!')
        fee_schedule_dao = FeeScheduleModel.find_by_filing_type_and_corp_type(
            corp_type, filing_type_code, valid_date)

        if not fee_schedule_dao:
            raise BusinessException(Error.PAY002)
        fee_schedule = FeeSchedule()
        fee_schedule._dao = fee_schedule_dao  # pylint: disable=protected-access

        current_app.logger.debug('>get_fees_by_corp_type_and_filing_type')
        return fee_schedule
Пример #2
0
    def delete_account(cls, auth_account_id: str) -> PaymentAccount:
        """Delete the payment account."""
        current_app.logger.debug('<delete_account')
        pay_account: PaymentAccountModel = PaymentAccountModel.find_by_auth_account_id(
            auth_account_id)
        cfs_account: CfsAccountModel = CfsAccountModel.find_effective_by_account_id(
            pay_account.id)
        # 1 - Check if account have any credits
        # 2 - Check if account have any PAD transactions done in last N (10) days.
        if pay_account.credit and pay_account.credit > 0:
            raise BusinessException(Error.OUTSTANDING_CREDIT)
        # Check if account is frozen.
        cfs_status: str = cfs_account.status if cfs_account else None
        if cfs_status == CfsAccountStatus.FREEZE.value:
            raise BusinessException(Error.FROZEN_ACCOUNT)
        if InvoiceModel.find_outstanding_invoices_for_account(
                pay_account.id, get_outstanding_txns_from_date()):
            # Check if there is any recent PAD transactions in N days.
            raise BusinessException(Error.TRANSACTIONS_IN_PROGRESS)

        # If CFS Account present, mark it as INACTIVE.
        if cfs_status and cfs_status != CfsAccountStatus.INACTIVE.value:
            cfs_account.status = CfsAccountStatus.INACTIVE.value
            # If account is active or pending pad activation stop PAD payments.
            if pay_account.payment_method == PaymentMethod.PAD.value \
                    and cfs_status in [CfsAccountStatus.ACTIVE.value, CfsAccountStatus.PENDING_PAD_ACTIVATION.value]:
                CFSService.suspend_cfs_account(cfs_account)
            cfs_account.save()

        if pay_account.statement_notification_enabled:
            pay_account.statement_notification_enabled = False
            pay_account.save()
    def create(**kwargs):
        """Create a subclass of PaymentSystemService based on input params."""
        current_app.logger.debug('<create')
        user: UserContext = kwargs['user']
        total_fees: int = kwargs.get('fees', None)
        payment_method = kwargs.get('payment_method', 'CC')
        corp_type = kwargs.get('corp_type', None)

        _instance: PaymentSystemService = None
        current_app.logger.debug('payment_method: {}, corp_type : {}'.format(
            payment_method, corp_type))

        if not payment_method and not corp_type:
            raise BusinessException(Error.PAY003)

        if total_fees == 0 or (Role.STAFF.value in user.roles):
            _instance = InternalPayService()
        else:
            if payment_method == 'CC':
                _instance = PaybcService()
            elif payment_method == 'PREMIUM':
                _instance = BcolService()

        if not _instance:
            raise BusinessException(Error.PAY003)

        return _instance
Пример #4
0
    def find_by_corp_type_and_filing_type(  # pylint: disable=too-many-arguments
            cls, corp_type: str, filing_type_code: str, valid_date: date,
            **kwargs):
        """Calculate fees for the filing by using the arguments."""
        current_app.logger.debug('<get_fees_by_corp_type_and_filing_type')
        if not corp_type and not filing_type_code:
            raise BusinessException(Error.PAY001)
        if kwargs.get('jurisdiction'):
            current_app.logger.warn('Not using Jurisdiction now!!!')

        fee_schedule_dao = FeeScheduleModel.find_by_filing_type_and_corp_type(
            corp_type, filing_type_code, valid_date)

        if not fee_schedule_dao:
            raise BusinessException(Error.PAY002)
        fee_schedule = FeeSchedule()
        fee_schedule._dao = fee_schedule_dao  # pylint: disable=protected-access

        if kwargs.get('is_priority') and fee_schedule_dao.priority_fee:
            fee_schedule.priority_fee = fee_schedule_dao.priority_fee.amount
        if kwargs.get('is_future_effective'
                      ) and fee_schedule_dao.future_effective_fee:
            fee_schedule.future_effective_fee = fee_schedule_dao.future_effective_fee.amount
        if kwargs.get('waive_fees'):
            fee_schedule.fee_amount = 0

        current_app.logger.debug('>get_fees_by_corp_type_and_filing_type')
        return fee_schedule
Пример #5
0
    def create(**kwargs):
        """Create a subclass of PaymentSystemService based on input params."""
        current_app.logger.debug('<create')
        user: UserContext = kwargs['user']
        total_fees: int = kwargs.get('fees', None)
        payment_method = kwargs.get('payment_method', 'CC')
        account_info = kwargs.get('account_info', None)

        _instance: PaymentSystemService = None
        current_app.logger.debug('payment_method: {}'.format(payment_method))

        if not payment_method:
            raise BusinessException(Error.INVALID_CORP_OR_FILING_TYPE)

        if total_fees == 0:
            _instance = InternalPayService()
        elif Role.STAFF.value in user.roles:
            if account_info is not None and account_info.get(
                    'bcolAccountNumber') is not None:
                _instance = BcolService()
            else:
                _instance = InternalPayService()
        else:
            if payment_method == 'CC':
                _instance = PaybcService()
            elif payment_method == 'DRAWDOWN':
                _instance = BcolService()

        if not _instance:
            raise BusinessException(Error.INVALID_CORP_OR_FILING_TYPE)

        return _instance
Пример #6
0
def _check_if_invoice_can_be_deleted(invoice: Invoice,
                                     payment: Payment = None):
    if invoice.invoice_status_code in (InvoiceStatus.PAID.value,
                                       InvoiceStatus.DELETED.value,
                                       InvoiceStatus.APPROVED.value):
        raise BusinessException(Error.COMPLETED_PAYMENT)
    if payment and payment.payment_status_code in (
            PaymentStatus.COMPLETED.value, PaymentStatus.DELETED.value):
        raise BusinessException(Error.COMPLETED_PAYMENT)
Пример #7
0
    def find_by_corp_type_and_filing_type(  # pylint: disable=too-many-arguments
            cls, corp_type: str, filing_type_code: str, valid_date: date,
            **kwargs):
        """Calculate fees for the filing by using the arguments."""
        current_app.logger.debug(
            f'<get_fees_by_corp_type_and_filing_type : {corp_type}, {filing_type_code}, '
            f'{valid_date}')
        user: UserContext = kwargs['user']

        if not corp_type and not filing_type_code:
            raise BusinessException(Error.INVALID_CORP_OR_FILING_TYPE)

        fee_schedule_dao = FeeScheduleModel.find_by_filing_type_and_corp_type(
            corp_type, filing_type_code, valid_date)

        if not fee_schedule_dao:
            raise BusinessException(Error.INVALID_CORP_OR_FILING_TYPE)

        fee_schedule = FeeSchedule()
        fee_schedule._dao = fee_schedule_dao  # pylint: disable=protected-access
        fee_schedule.quantity = kwargs.get('quantity')

        # Find fee overrides for account.
        account_fee = AccountFeeModel.find_by_auth_account_id_and_corp_type(
            user.account_id, corp_type)

        apply_filing_fees: bool = account_fee.apply_filing_fees if account_fee else True
        if not apply_filing_fees:
            fee_schedule.fee_amount = 0
            fee_schedule.waived_fee_amount = 0

        # Set transaction fees
        fee_schedule.service_fees = FeeSchedule.calculate_service_fees(
            fee_schedule_dao, account_fee)

        # Special case for CSO partner type which is different from normal flow
        if fee_schedule.corp_type_code == 'CSO' and fee_schedule.quantity:
            fee_schedule.service_fees = fee_schedule.service_fees * fee_schedule.quantity

        if kwargs.get(
                'is_priority'
        ) and fee_schedule_dao.priority_fee and apply_filing_fees:
            fee_schedule.priority_fee = fee_schedule_dao.priority_fee.amount
        if kwargs.get(
                'is_future_effective'
        ) and fee_schedule_dao.future_effective_fee and apply_filing_fees:
            fee_schedule.future_effective_fee = fee_schedule_dao.future_effective_fee.amount

        if kwargs.get('waive_fees'):
            fee_schedule.fee_amount = 0
            fee_schedule.priority_fee = 0
            fee_schedule.future_effective_fee = 0
            fee_schedule.service_fees = 0

        current_app.logger.debug('>get_fees_by_corp_type_and_filing_type')
        return fee_schedule
Пример #8
0
    def create_from_payment_method(payment_method: str):
        """Create the payment system implementation from payment method."""
        _instance: PaymentSystemService = None
        if payment_method == PaymentMethod.DIRECT_PAY.value:
            _instance = DirectPayService()
        elif payment_method == PaymentMethod.CC.value:
            _instance = PaybcService()
        elif payment_method == PaymentMethod.DRAWDOWN.value:
            _instance = BcolService()
        elif payment_method == PaymentMethod.INTERNAL.value:
            _instance = InternalPayService()
        elif payment_method == PaymentMethod.ONLINE_BANKING.value:
            _instance = OnlineBankingService()
        elif payment_method == PaymentMethod.PAD.value:
            _instance = PadService()
        elif payment_method == PaymentMethod.EFT.value:
            _instance = EftService()
        elif payment_method == PaymentMethod.WIRE.value:
            _instance = WireService()
        elif payment_method == PaymentMethod.EJV.value:
            _instance = EjvPayService()

        if not _instance:
            raise BusinessException(Error.INVALID_CORP_OR_FILING_TYPE)
        return _instance
Пример #9
0
    def create(invoice_id: int, fee: FeeSchedule, **kwargs):
        """Create Payment Line Item record."""
        current_app.logger.debug('<create')
        user: UserContext = kwargs['user']
        p = PaymentLineItem()
        p.invoice_id = invoice_id
        p.total = fee.total
        p.fee_schedule_id = fee.fee_schedule_id
        p.description = fee.description
        p.filing_fees = fee.fee_amount
        p.gst = fee.gst
        p.priority_fees = fee.priority_fee
        p.pst = fee.pst
        p.future_effective_fees = fee.future_effective_fee
        p.quantity = fee.quantity
        p.line_item_status_code = Status.CREATED.value
        if fee.waived_fee_amount > 0:
            if user.has_role(Role.STAFF.value):
                p.waived_fees = fee.waived_fee_amount
                p.waived_by = user.user_name
            else:
                raise BusinessException(Error.PAY003)
        p_dao = p.flush()

        p = PaymentLineItem()
        p._dao = p_dao  # pylint: disable=protected-access

        current_app.logger.debug('>create')
        return p
Пример #10
0
    def create_refund(cls, invoice_id: int, request: Dict[str, str],
                      **kwargs) -> Dict[str, str]:
        """Create refund."""
        current_app.logger.debug(f'Starting refund : {invoice_id}')
        # Do validation by looking up the invoice
        invoice: InvoiceModel = InvoiceModel.find_by_id(invoice_id)

        paid_statuses = (InvoiceStatus.PAID.value,
                         InvoiceStatus.APPROVED.value,
                         InvoiceStatus.UPDATE_REVENUE_ACCOUNT.value)

        if invoice.invoice_status_code not in paid_statuses:
            current_app.logger.info(
                f'Cannot process refund as status of {invoice_id} is {invoice.invoice_status_code}'
            )
            raise BusinessException(Error.INVALID_REQUEST)

        refund: RefundService = RefundService()
        refund.invoice_id = invoice_id
        refund.reason = get_str_by_path(request, 'reason')
        refund.requested_by = kwargs['user'].user_name
        refund.requested_date = datetime.now()
        refund.flush()
        pay_system_service: PaymentSystemService = PaymentSystemFactory.create_from_payment_method(
            payment_method=invoice.payment_method_code)
        invoice_status = pay_system_service.process_cfs_refund(invoice)
        message = REFUND_SUCCESS_MESSAGES.get(
            f'{invoice.payment_method_code}.{invoice.invoice_status_code}')
        # set invoice status
        invoice.invoice_status_code = invoice_status or InvoiceStatus.REFUND_REQUESTED.value
        invoice.refund = invoice.total  # no partial refund
        invoice.save()
        current_app.logger.debug(f'Completed refund : {invoice_id}')
        return {'message': message}
Пример #11
0
 def _validate_redirect_url_and_throw_error(payment_method: str,
                                            return_url: str):
     """Check and Throw if the return_url is not a valid url."""
     is_validity_check_needed = payment_method in (
         PaymentMethod.CC.value, PaymentMethod.DIRECT_PAY.value)
     if is_validity_check_needed and not is_valid_redirect_url(return_url):
         raise BusinessException(Error.INVALID_REDIRECT_URI)
Пример #12
0
    def create_refund(cls, invoice_id: int, request: Dict[str, str],
                      **kwargs) -> None:
        """Create refund."""
        current_app.logger.debug('<create refund')
        # Do validation by looking up the invoice
        invoice: InvoiceModel = InvoiceModel.find_by_id(invoice_id)
        # Allow refund only for direct pay payments, and only if the status of invoice is PAID/UPDATE_REVENUE_ACCOUNT
        paid_statuses = (InvoiceStatus.PAID.value,
                         InvoiceStatus.APPROVED.value,
                         InvoiceStatus.UPDATE_REVENUE_ACCOUNT.value)

        if invoice.invoice_status_code not in paid_statuses:
            raise BusinessException(Error.INVALID_REQUEST)

        refund: RefundService = RefundService()
        refund.invoice_id = invoice_id
        refund.reason = get_str_by_path(request, 'reason')
        refund.requested_by = kwargs['user'].user_name
        refund.requested_date = datetime.now()
        refund.flush()

        cls._process_cfs_refund(invoice)

        # set invoice status
        invoice.invoice_status_code = InvoiceStatus.REFUND_REQUESTED.value
        invoice.refund = invoice.total  # no partial refund
        invoice.save()
Пример #13
0
    def create_receipt(payment_identifier: str, invoice_identifier: str, filing_data: Dict[str, Any],
                       skip_auth_check: bool = False, **kwargs):
        """Create receipt."""
        current_app.logger.debug('<create receipt initiated')
        receipt_dict = {
            'templateName': 'payment_receipt',
            'reportName': filing_data.pop('fileName', 'payment_receipt')
        }

        template_vars = {}
        template_vars.update(filing_data)

        # invoice number not mandatory ;since only one invoice exist for a payment now
        if not invoice_identifier:
            invoice_data = Invoice.find_by_payment_identifier(payment_identifier, skip_auth_check=skip_auth_check)
        else:
            invoice_data = Invoice.find_by_id(invoice_identifier, payment_identifier, skip_auth_check=skip_auth_check)

        payment_account = PaymentAccount.find_by_pay_system_id(
            credit_account_id=invoice_data.credit_account_id,
            internal_account_id=invoice_data.internal_account_id,
            bcol_account_id=invoice_data.bcol_account_id)

        invoice_reference = InvoiceReference.find_completed_reference_by_invoice_id(invoice_data.id)

        # template_vars['incorporationNumber'] = payment_account.corp_number
        template_vars['invoiceNumber'] = invoice_reference.invoice_number

        if payment_account.payment_system_code == PaymentSystem.INTERNAL.value and invoice_data.routing_slip:
            template_vars['routingSlipNumber'] = invoice_data.routing_slip

        if not invoice_data.receipts:
            raise BusinessException(Error.INVALID_REQUEST)

        template_vars['receiptNo'] = invoice_data.receipts[0].receipt_number
        template_vars['filingIdentifier'] = filing_data.get('filingIdentifier', invoice_data.filing_id)

        if invoice_data.bcol_account_id:
            bcol_account: BcolPaymentAccountModel = BcolPaymentAccountModel.find_by_id(invoice_data.bcol_account_id)
            template_vars['bcOnlineAccountNumber'] = bcol_account.bcol_account_id

        payment_method = PaymentModel.find_payment_method_by_payment_id(payment_identifier)

        # TODO fix properly later
        if not invoice_data.internal_account_id:
            template_vars['paymentMethod'] = payment_method.description

        template_vars['invoice'] = camelcase_dict(invoice_data.asdict(), {})

        receipt_dict['templateVars'] = template_vars

        current_app.logger.debug(
            '<OAuthService invoked from receipt.py {}'.format(current_app.config.get('REPORT_API_BASE_URL')))

        pdf_response = OAuthService.post(current_app.config.get('REPORT_API_BASE_URL'),
                                         kwargs['user'].bearer_token, AuthHeaderType.BEARER,
                                         ContentType.JSON, receipt_dict)
        current_app.logger.debug('<OAuthService responded to receipt.py')

        return pdf_response
Пример #14
0
    def get_receipt_details(filing_data, invoice_identifier, skip_auth_check):
        """Return receipt details."""
        receipt_details: dict = {}
        # invoice number mandatory
        invoice_data = Invoice.find_by_id(invoice_identifier,
                                          skip_auth_check=skip_auth_check)

        is_pending_pad_invoice = invoice_data.payment_method_code == PaymentMethod.PAD.value and \
            invoice_data.invoice_status_code != InvoiceStatus.PAID.value
        if not is_pending_pad_invoice and not invoice_data.receipts:
            raise BusinessException(Error.INVALID_REQUEST)

        invoice_reference = InvoiceReference.find_completed_reference_by_invoice_id(
            invoice_data.id)

        receipt_details['invoiceNumber'] = invoice_reference.invoice_number
        if invoice_data.payment_method_code == PaymentSystem.INTERNAL.value and invoice_data.routing_slip:
            receipt_details['routingSlipNumber'] = invoice_data.routing_slip
        receipt_details[
            'receiptNumber'] = None if is_pending_pad_invoice else invoice_data.receipts[
                0].receipt_number
        receipt_details['filingIdentifier'] = filing_data.get(
            'filingIdentifier', invoice_data.filing_id)
        receipt_details['bcOnlineAccountNumber'] = invoice_data.bcol_account

        payment_method = PaymentMethodModel.find_by_code(
            invoice_data.payment_method_code)

        receipt_details['paymentMethod'] = payment_method.code
        if invoice_data.payment_method_code != PaymentSystem.INTERNAL.value:
            receipt_details[
                'paymentMethodDescription'] = payment_method.description
        receipt_details['invoice'] = camelcase_dict(invoice_data.asdict(), {})
        return receipt_details
Пример #15
0
    def create(payment_identifier: str, request_json: Dict):
        """Create transaction record."""
        current_app.logger.debug('<create transaction')
        # Lookup payment record
        payment: Payment = Payment.find_by_id(payment_identifier,
                                              skip_auth_check=True)

        # Check if return url is valid
        return_url = request_json.get('clientSystemUrl')
        if payment.payment_system_code == PaymentSystem.PAYBC.value and not is_valid_redirect_url(
                return_url):
            raise BusinessException(Error.PAY013)

        if not payment.id:
            raise BusinessException(Error.PAY005)
        # Cannot start transaction on completed payment
        if payment.payment_status_code in (Status.COMPLETED.value,
                                           Status.DELETED.value,
                                           Status.DELETE_ACCEPTED.value):
            raise BusinessException(Error.PAY006)

        # If there are active transactions (status=CREATED), then invalidate all of them and create a new one.
        existing_transactions = PaymentTransactionModel.find_by_payment_id(
            payment.id)
        if existing_transactions:
            for existing_transaction in existing_transactions:
                if existing_transaction.status_code != Status.CANCELLED.value:
                    existing_transaction.status_code = Status.CANCELLED.value
                    existing_transaction.transaction_end_time = datetime.now()
                    existing_transaction.save()

        transaction = PaymentTransaction()
        transaction.payment_id = payment.id
        transaction.client_system_url = return_url
        transaction.status_code = Status.CREATED.value
        transaction_dao = transaction.flush()
        transaction._dao = transaction_dao  # pylint: disable=protected-access
        transaction.pay_system_url = transaction.build_pay_system_url(
            payment, transaction.id, request_json.get('payReturnUrl'))
        transaction_dao = transaction.save()

        transaction = PaymentTransaction()
        transaction._dao = transaction_dao  # pylint: disable=protected-access
        current_app.logger.debug('>create transaction')

        return transaction
Пример #16
0
 def create_routing_slip_refund(cls, routing_slip_number: str,
                                request: Dict[str, str],
                                **kwargs) -> Dict[str, str]:
     """Create Routing slip refund."""
     current_app.logger.debug('<create Routing slip  refund')
     #
     # check if routing slip exists
     # validate user role -> update status of routing slip
     # check refunds table
     #   if Yes ; update the data [only with whatever is in payload]
     #   if not ; create new entry
     # call cfs
     rs_model = RoutingSlipModel.find_by_number(routing_slip_number)
     if not rs_model:
         raise BusinessException(Error.RS_DOESNT_EXIST)
     reason = get_str_by_path(request, 'reason')
     if (refund_status := get_str_by_path(request, 'status')) is None:
         raise BusinessException(Error.INVALID_REQUEST)
Пример #17
0
    def create_invoice(self, payment_account: PaymentAccount,  # pylint: disable=too-many-locals
                       line_items: [PaymentLineItem], invoice: Invoice, **kwargs):
        """Create Invoice in PayBC."""
        current_app.logger.debug('<create_invoice')
        user: UserContext = kwargs['user']
        pay_endpoint = current_app.config.get('BCOL_API_ENDPOINT') + '/payments'
        corp_number = invoice.business_identifier
        amount_excluding_txn_fees = sum(line.total for line in line_items)
        filing_types = ','.join([item.filing_type_code for item in line_items])
        remarks = f'{corp_number}({filing_types})'
        if user.first_name:
            remarks = f'{remarks}-{user.first_name}'

        payload: Dict = {
            # 'userId': payment_account.bcol_user_id if payment_account.bcol_user_id else 'PE25020',
            'userId': payment_account.bcol_user_id,
            'invoiceNumber': str(invoice.id),
            'folioNumber': invoice.folio_number,
            'amount': str(amount_excluding_txn_fees),
            'rate': str(amount_excluding_txn_fees),
            'remarks': remarks[:50],
            'feeCode': self._get_fee_code(kwargs.get('corp_type_code'), user.is_staff() or user.is_system())
        }

        if user.is_staff() or user.is_system():
            payload['userId'] = user.user_name_with_no_idp if user.is_staff() else current_app.config[
                'BCOL_USERNAME_FOR_SERVICE_ACCOUNT_PAYMENTS']
            payload['accountNumber'] = payment_account.bcol_account_id
            payload['formNumber'] = invoice.dat_number
            payload['reduntantFlag'] = 'Y'
            payload['rateType'] = 'C'

        if payload.get('folioNumber', None) is None:  # Set empty folio if None
            payload['folioNumber'] = ''
        try:
            pay_response = self.post(pay_endpoint, user.bearer_token, AuthHeaderType.BEARER, ContentType.JSON,
                                     payload, raise_for_error=False)
            response_json = pay_response.json()
            current_app.logger.debug(response_json)
            pay_response.raise_for_status()
        except HTTPError as bol_err:
            current_app.logger.error(bol_err)
            error_type: str = response_json.get('type')
            if error_type.isdigit():
                error = get_bcol_error(int(error_type))
            else:
                error = Error.BCOL_ERROR
            raise BusinessException(error)

        invoice = {
            'invoice_number': response_json.get('key'),
            'reference_number': response_json.get('sequenceNo'),
            'totalAmount': -(int(response_json.get('totalAmount', 0)) / 100)
        }
        current_app.logger.debug('>create_invoice')
        return invoice
Пример #18
0
 def get_payment(cls, payment_id):
     """Get payment related records."""
     try:
         payment: Payment = Payment.find_by_id(payment_id)
         if not payment.id:
             raise BusinessException(Error.PAY005)
         return payment.asdict()
     except Exception as e:
         current_app.logger.debug('Error on get payment {}', e)
         raise
Пример #19
0
    def find_account(cls, business_info: Dict[str, Any],
                     authorization: Dict[str, Any],
                     payment_system: str, **kwargs):
        """Find payment account by corp number, corp type and payment system code."""
        current_app.logger.debug('<find_payment_account')
        user: UserContext = kwargs['user']
        auth_account_id: str = get_str_by_path(authorization, 'account/id')
        bcol_user_id: str = get_str_by_path(authorization, 'account/paymentPreference/bcOnlineUserId')
        bcol_account_id: str = get_str_by_path(authorization, 'account/paymentPreference/bcOnlineAccountId')
        corp_number: str = business_info.get('businessIdentifier')
        corp_type: str = business_info.get('corpType')

        account_dao = None

        if payment_system == PaymentSystem.BCOL.value:
            # If BCOL payment and if the payment is inititated by customer check if bcol_user_id is present
            # Staff and system can make payments for users with no bcol account
            if not user.is_system() and not user.is_staff() and bcol_user_id is None:
                raise BusinessException(Error.INCOMPLETE_ACCOUNT_SETUP)

            account_dao: BcolPaymentAccount = BcolPaymentAccount.find_by_bcol_user_id_and_account(
                auth_account_id=auth_account_id,
                bcol_user_id=bcol_user_id,
                bcol_account_id=bcol_account_id
            )
        elif payment_system == PaymentSystem.INTERNAL.value:
            account_dao: InternalPaymentAccount = InternalPaymentAccount. \
                find_by_corp_number_and_corp_type_and_account_id(corp_number=corp_number, corp_type=corp_type,
                                                                 account_id=auth_account_id
                                                                 )
        elif payment_system == PaymentSystem.PAYBC.value:
            if not corp_number and not corp_type:
                raise BusinessException(Error.INVALID_CORP_OR_FILING_TYPE)
            account_dao = CreditPaymentAccount.find_by_corp_number_and_corp_type_and_auth_account_id(
                corp_number=corp_number,
                corp_type=corp_type,
                auth_account_id=auth_account_id
            )
        payment_account = PaymentAccount()
        payment_account.populate(account_dao)  # pylint: disable=protected-access

        current_app.logger.debug('>find_payment_account')
        return payment_account
Пример #20
0
 def _validate_and_throw_error(instance: PaymentSystemService,
                               payment_account: PaymentAccount):
     if isinstance(instance, PadService):
         is_in_pad_confirmation_period = payment_account.pad_activation_date > datetime.now(
         )
         is_cfs_account_in_pending_status = payment_account.cfs_account_status == \
             CfsAccountStatus.PENDING_PAD_ACTIVATION.value
         if is_in_pad_confirmation_period or is_cfs_account_in_pending_status:
             raise BusinessException(
                 Error.ACCOUNT_IN_PAD_CONFIRMATION_PERIOD)
Пример #21
0
    def create(payment_method: str = None,
               corp_type: str = None,
               payment_system: str = None):
        """Create a subclass of PaymentSystemService based on input params."""
        current_app.logger.debug('<create')

        _instance: PaymentSystemService = None
        current_app.logger.debug('payment_method: {}, corp_type : {}'.format(
            payment_method, corp_type))
        if not payment_method and not corp_type and not payment_system:
            raise BusinessException(Error.PAY003)

        if (payment_method == 'CC'
                and corp_type == 'CP') or payment_system == 'PAYBC':
            _instance = PaybcService()
        else:
            raise BusinessException(Error.PAY003)

        return _instance
Пример #22
0
    def create(**kwargs):
        """Create a subclass of PaymentSystemService based on input params."""
        current_app.logger.debug('<create')
        user: UserContext = kwargs['user']
        total_fees: int = kwargs.get('fees', None)
        payment_account: PaymentAccount = kwargs.get('payment_account', None)
        payment_method = kwargs.get(
            'payment_method', PaymentMethod.DIRECT_PAY.value
            if current_app.config.get('DIRECT_PAY_ENABLED') else
            PaymentMethod.CC.value)
        account_info = kwargs.get('account_info', None)
        has_bcol_account_number = account_info is not None and account_info.get(
            'bcolAccountNumber') is not None

        _instance: PaymentSystemService = None
        current_app.logger.debug('payment_method: {}'.format(payment_method))

        if not payment_method:
            raise BusinessException(Error.INVALID_CORP_OR_FILING_TYPE)

        if total_fees == 0:
            _instance = InternalPayService()
        elif Role.STAFF.value in user.roles:
            if has_bcol_account_number:
                _instance = BcolService()
            else:
                _instance = InternalPayService()
        else:
            # System accounts can create BCOL payments similar to staff by providing as payload
            if has_bcol_account_number and Role.SYSTEM.value in user.roles:
                _instance = BcolService()
            else:
                _instance = PaymentSystemFactory.create_from_payment_method(
                    payment_method)

        if not _instance:
            raise BusinessException(Error.INVALID_CORP_OR_FILING_TYPE)

        PaymentSystemFactory._validate_and_throw_error(_instance,
                                                       payment_account)

        return _instance
Пример #23
0
    def create(payment_identifier: str,
               redirect_uri: str,
               jwt: JwtManager = None,
               skip_auth_check: bool = False):
        """Create transaction record."""
        current_app.logger.debug('<create transaction')
        # Lookup payment record
        payment: Payment = Payment.find_by_id(payment_identifier,
                                              jwt=jwt,
                                              one_of_roles=[EDIT_ROLE],
                                              skip_auth_check=skip_auth_check)

        if not payment.id:
            raise BusinessException(Error.PAY005)
        if payment.payment_status_code == Status.COMPLETED.value:  # Cannot start transaction on completed payment
            raise BusinessException(Error.PAY006)

        # If there are active transactions (status=CREATED), then invalidate all of them and create a new one.
        existing_transactions = PaymentTransactionModel.find_by_payment_id(
            payment.id)
        if existing_transactions:
            for existing_transaction in existing_transactions:
                if existing_transaction.status_code != Status.CANCELLED.value:
                    existing_transaction.status_code = Status.CANCELLED.value
                    existing_transaction.transaction_end_time = datetime.now()
                    existing_transaction.save()

        transaction = PaymentTransaction()
        transaction.payment_id = payment.id
        transaction.client_system_url = redirect_uri
        transaction.status_code = Status.CREATED.value
        transaction_dao = transaction.flush()
        transaction._dao = transaction_dao  # pylint: disable=protected-access
        transaction.pay_system_url = transaction.build_pay_system_url(
            payment, transaction.id)
        transaction_dao = transaction.save()

        transaction = PaymentTransaction()
        transaction._dao = transaction_dao  # pylint: disable=protected-access
        current_app.logger.debug('>create transaction')

        return transaction
Пример #24
0
    def find_by_id(payment_identifier: int, transaction_id: uuid):
        """Find transaction by id."""
        transaction_dao = PaymentTransactionModel.find_by_id_and_payment_id(transaction_id, payment_identifier)
        if not transaction_dao:
            raise BusinessException(Error.INVALID_TRANSACTION_ID)

        transaction = PaymentTransaction()
        transaction._dao = transaction_dao  # pylint: disable=protected-access

        current_app.logger.debug('>find_by_id')
        return transaction
Пример #25
0
    def find_by_id(transaction_id: uuid):
        """Find transaction by id."""
        current_app.logger.debug(f'>find_by_id {transaction_id}')
        transaction_dao = PaymentTransactionModel.find_by_id(transaction_id)
        if not transaction_dao:
            raise BusinessException(Error.INVALID_TRANSACTION_ID)

        transaction = PaymentTransaction.__wrap_dao(transaction_dao)

        current_app.logger.debug('>find_by_id')
        return transaction
Пример #26
0
    def find_by_id(account_id: int):
        """Find account by id."""
        account_dao = PaymentAccountModel.find_by_id(account_id)
        if not account_dao:
            raise BusinessException(Error.PAY009)

        account = PaymentAccount()
        account._dao = account_dao  # pylint: disable=protected-access

        current_app.logger.debug('>find_by_id')
        return account
Пример #27
0
    def create_receipt(payment_identifier: str, invoice_identifier: str,
                       filing_data: Tuple[Dict[str, Any]], user_jwt: str):
        """Create receipt."""
        current_app.logger.debug('<create receipt initiated',
                                 payment_identifier, invoice_identifier)
        receipt_dict = {
            'templateVars': {
                'lineItems': [],
            },
            'templateName': 'payment_receipt_coops',
            'reportName': 'payment_receipt_coops'
        }
        template_vars = receipt_dict['templateVars']
        template_vars['coopsName'] = filing_data.get('corpName')
        template_vars['filingDateTime'] = filing_data.get('filingDateTime')
        # inovice number not mandatory ;since only one invoice exist for a payment now
        if not invoice_identifier:
            invoice_data = Invoice.find_by_payment_identifier(
                payment_identifier).asdict()
        else:
            invoice_data = Invoice.find_by_id(invoice_identifier,
                                              payment_identifier).asdict()

        template_vars['incorporationNumber'] = invoice_data['created_by']
        template_vars['paymentInvoiceNumber'] = invoice_data['invoice_number']
        if 'receipts' not in invoice_data:
            raise BusinessException(Error.PAY999)

        template_vars['receiptNumber'] = invoice_data['receipts'][0][
            'receipt_number']
        for line_item in invoice_data['line_items']:
            template_vars['lineItems'].append({
                'description':
                line_item['description'],
                'filingFees':
                '{:.2f}'.format(line_item['total'])
            })

        template_vars['lineItems'].append({
            'description':
            'Total',
            'filingFees':
            '{:.2f}'.format(invoice_data['total'])
        })
        current_app.logger.debug('<OAuthService invoked from receipt.py',
                                 current_app.config.get('REPORT_API_BASE_URL'))

        pdf_response = OAuthService.post(
            current_app.config.get('REPORT_API_BASE_URL'), user_jwt,
            AuthHeaderType.BEARER, ContentType.JSON, receipt_dict)
        current_app.logger.debug('<OAuthService responded to receipt.py')

        return pdf_response
Пример #28
0
 def create_from_system_code(payment_system: str):
     """Create the payment system implementation from the payment system code."""
     _instance: PaymentSystemService = None
     if payment_system == PaymentSystem.PAYBC.value:
         _instance = PaybcService()
     elif payment_system == PaymentSystem.BCOL.value:
         _instance = BcolService()
     elif payment_system == PaymentSystem.INTERNAL.value:
         _instance = InternalPayService()
     if not _instance:
         raise BusinessException(Error.PAY003)
     return _instance
Пример #29
0
    def _validate_routing_slip_number_digits(rs_number: str):
        if len(rs_number) != 9 or not rs_number.isdigit():
            raise BusinessException(Error.FAS_INVALID_ROUTING_SLIP_DIGITS)

        # Using the first 8 digits of the routing slip
        data_digits = list(map(int, rs_number[:8]))
        validation_digit = int(rs_number[8])
        # For every 2nd digit:
        # -- Multiply the digit by 2
        # -- If the sum is 2 digits, add the two digits together (this will always be a 1 digit number in this case)
        replacement_digits = [int(str(x)[0]) + int(str(x)[1]) if x >
                              9 else x for x in [i * 2 for i in data_digits[1::2]]]
        # -- Substitute the resulting digit for the original digit in the iteration
        replacement_digits.reverse()
        data_digits[1::2] = replacement_digits[:len(data_digits[1::2])]
        # Add all numbers together (of the 8 digits)
        # Subtract the 2nd digit of the sum from 10
        checksum = ((10 - (sum(data_digits) % 10)) % 10)
        # The difference should equal the 9th digit of the routing slip ID
        if validation_digit != checksum:
            raise BusinessException(Error.FAS_INVALID_ROUTING_SLIP_DIGITS)
Пример #30
0
    def _validate_linking(routing_slip: RoutingSlipModel, parent_rs_slip: RoutingSlipModel) -> None:
        """Validate the linking.

        1). child already has a parent/already linked.
        2). its already a parent.
        3). parent_rs_slip has a parent.ie parent_rs_slip shouldn't already be linked
        4). one of them has transactions
        """
        if RoutingSlip._is_linked_already(routing_slip):
            raise BusinessException(Error.RS_ALREADY_LINKED)

        children = RoutingSlipModel.find_children(routing_slip.number)
        if children and len(children) > 0:
            raise BusinessException(Error.RS_ALREADY_A_PARENT)

        if RoutingSlip._is_linked_already(parent_rs_slip):
            raise BusinessException(Error.RS_PARENT_ALREADY_LINKED)

        # prevent self linking

        if routing_slip.number == parent_rs_slip.number:
            raise BusinessException(Error.RS_CANT_LINK_TO_SAME)

        # has one of these has pending
        if routing_slip.invoices:
            raise BusinessException(Error.RS_CHILD_HAS_TRANSACTIONS)

        # Stop the user from linking NSF. NSF can only be a parent.
        if routing_slip.status == RoutingSlipStatus.NSF.value:
            raise BusinessException(Error.RS_CANT_LINK_NSF)

        RoutingSlip._validate_status(parent_rs_slip, routing_slip)