# Anton's board
## 2020.09.04
Transactions: Payments, Prs, Invoices, ...
Entries: Debit/Credit
Txn: DebitTxn/CreditTxn
Submission: DebitTxnSubmission/CreditTxnSubmission
# Other
Trans
Initiator bank account for Transfer must be the one which will later be used in DebitTxn grouping.
It must be
Bank Account
-> debit_processing_banks: [nab_de]
-> credit_processing_banks: [nab_npp, nab_de]
Debit -> Initiator Bank Account
Debit.with_initiator_processing_banks(banks)
Proposed solution A:
Currently we are relying on Debit.with_initiator_processing_banks scope
It's possible to adjust it with new logic, but it's will be too complicated IMO
Instead we should add new column Debit.first_processing_bank and set the value
So we can do fast and simple query later.
Proposed solution B:
Debit.virtual_bank_involved
Debit.initiator_processing_banks
Debit.recipient_processing_banks
### Submission Example
Debit.initiator_bank_account (Bank A) + Rule -> config
Debit.initiator_bank_account (Bank B) -> config
Credit processing bank
- usual: copy from Debit
- new: if bank_account is virtual then use virtual_bank processing bank
Cigno
- bank A - real bank account - wbc_t3 processing bank
- bank B - Virtual Bank Account
- [nab] - debit processing bank
- [npp, nab] - credit processing bank
Money flow: Debit -> Control Account -> Credit
### Top up transfer transaction
Debit (from real bank account): [nab] - debiting merchant bank account A and the processing bank comes from config on bank B
Credit (to Virtual Bank Account): [virtual_bank]
### Withdraw transfer transaction
Debit (from Virtual Bank Account): [virtual_bank]
Credit (to real bank account): [npp, nab] - crediting contact bank account and the processing bank comes from config on bank B
Edge case:
Credit reversal (to Virtual Bank Account): [virtual_bank]
### Rule
When there is a transaction including a Virtual Bank Account, the processing bank should be the one configured on the Virtual Bank Account.
Select *
From debits
where
(
# Top-up
Debit.initiator_bank_account_id != Debit.from_bank_account_id
AND initiator_bank_account.processing_bank.first == query
AND debit.source_type == 'Transfer'
AND initiator_bank_account.processing_bank.first == query
)
OR (
# Withdrawal
Debit.initiator_bank_account_id == Debit.from_bank_account_id
AND debit.source_type == 'Transfer'
AND query == 'virtual'
# OR
Debit.from_bank_account_id is virtual
AND query == 'virtual'
)
OR (
# The rest
initiator_bank_account.processing_bank.first == query
)
# Proposal Solution A
* Add Debit.initiator_bank_account_id column
* Debit.initiator_bank_account_id will be different for Top-up and Withdraw transactions
## Top-up
Debit join Virtual bank account and take config -> nab
Credit
- if bank_account is virtual then use virtual_bank processing bank
- otherwise copy from Debit
if Debit.initiator_bank_account_id != Debit.from_bank_account_id
use initiator_bank_account config
## Withdraw
Debit joins Virtual bank account and take config -> nab , but it should be 'virtual'
- lookup query should have a conditional to check if bank account is virtual and always return 'virtual' in that case
Credit
- if debit is virtual then use debit.initiator_bank_account.credit_processing_bank
- otherwise copy from Debit
if Debit.initiator_bank_account_id == Debit.from_bank_account_id
always 'virtual'
# Proposal Solution B
Debit processing banks
* Add Debit.first_processing_bank column
* maybe Debit::Matured
* Add Debit.actual_processing_bank column
* Include Proposal Solution A
* When bank account config is changed we need to refresh Debit.first_processing_bank
* Debit.initiator_bank_account ??
* Default processing bank
- we can make it work, if we store Debit.first_processing_bank == 'default'
* Race condition to deal with
Mature on Saturday -> nab
Config change on Sunday -> wbc
Submit on Monday -> should be wbc, but will nab
## Proposed solution C
* calculate processing bank in ruby and not SQL
```
Creating a TransferTxn
from_bank_account: bank A (real)
to_bank_account: bank B (virtual)
Debit.processing_bank
- should use bank B processing bank config (so it sits in control account)
Credit.processing
- virtual
```
# Policy authorisation
```ruby
policy = PaymentPolicy.new
Payment Refund
if payment.can_be_refunded? # Is it doable at all? Can account owner do it?
- can_I_refund = policy(@payment).refund? # Can YOU do it
- css = can_I_refund ? '' : 'disabled'
= button_to 'Refund', url, class: css
account - can anybody in my account refund the payment? (includes Feature flags)
permission - can I refund the payment?
object - can payment be refunded? (excludes Feature flags) #e.g. state check of debit/credit
pundit_user + record
Policy checks
- role
- object
- feature flag
Command checks
- inputs
- limit checks
policy(): role, object, feature flag
account_policy(): object, feature flag
object_policy(): object
* account_policy(@payment).refund?
* policy(@payment).refund?()
* policy(@payment).refund?(:role, :object, :flag)
* policy(@payment).refund?(:account)
* policy(@payment).refund?(for: :account)
* policy(@payment).refund?(checks: :object)
* policy(@payment).refund?(roles: false)
* policy(@payment).refund?(:object)
* policy(@payment).refund?(skip_roles: true)
* policy(@payment).account.refund?
* policy(@payment).object.refund?
* policy(@payment).anybody.refund?
can I create payment?
policy(Payment).create?
policy(Payment.new).create?
policy(account.payments.new).create?
auth_css(....)
* enable_button_css(policy(@payment).refund?)
* policy(@payment).refund?(:button_css)
* policy(@payment).button_css(:refund?)
* ~~policy(@payment).button_css.refund?~~
* disabled_button_css(policy(@payment).refund?)
* auth_check_css(policy(@payment).refund?)
= link_to 'Refund', url, policy: policy(@payment).refund?, class: 'this that'
-> class: 'this that disabled'
= form_for ...., policy: policy(@payment).refund?
= simple_form_for ...., policy: policy(@payment).refund?
= authorised_form_for import_file, command: Command::ImportFile::Add
policy(ImportFile).add?
```
## High level flow overview
Traditional web app:
Ajay (Browser) -> Controller -> DB
Sync:
Ajay (Browser) -> Controller -> Command -> Event -> Projector -> DB
-> Reactor (1 off action) -> Event -> Project/Reactor
Async:
Ajay (Browser) -> Controller -> Command -> Event
Event -> DB