---
# System prepended metadata

title: Anton's board

---

# 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



