diff --git a/src/subdomains/core/sell-crypto/process/__tests__/buy-fiat.entity.spec.ts b/src/subdomains/core/sell-crypto/process/__tests__/buy-fiat.entity.spec.ts new file mode 100644 index 0000000000..954239b405 --- /dev/null +++ b/src/subdomains/core/sell-crypto/process/__tests__/buy-fiat.entity.spec.ts @@ -0,0 +1,58 @@ +import { createCustomAsset } from 'src/shared/models/asset/__mocks__/asset.entity.mock'; +import { createCustomFiat } from 'src/shared/models/fiat/__mocks__/fiat.entity.mock'; +import { createCustomSell } from 'src/subdomains/core/sell-crypto/route/__mocks__/sell.entity.mock'; +import { createCustomBank, olkyEUR, yapealCHF } from 'src/subdomains/supporting/bank/bank/__mocks__/bank.entity.mock'; +import { IbanBankName } from 'src/subdomains/supporting/bank/bank/dto/bank.dto'; +import { createCustomFiatOutput } from 'src/subdomains/supporting/fiat-output/__mocks__/fiat-output.entity.mock'; +import { createCustomBuyFiat } from '../__mocks__/buy-fiat.entity.mock'; + +describe('BuyFiat', () => { + describe('pendingOutputAmount', () => { + const chfYapealAsset = createCustomAsset({ name: 'CHF', dexName: 'CHF', bank: yapealCHF }); + const eurOlkyAsset = createCustomAsset({ name: 'EUR', dexName: 'EUR', bank: olkyEUR }); + + it('counts the output as liability while transmitted but not yet completed (Yapeal)', () => { + const buyFiat = createCustomBuyFiat({ + outputAmount: 14980.12, + sell: createCustomSell({ fiat: createCustomFiat({ name: 'CHF' }) }), + fiatOutput: createCustomFiatOutput({ + bank: createCustomBank({ name: IbanBankName.YAPEAL, currency: 'CHF' }), + isTransmittedDate: new Date(), + }), + }); + + expect(buyFiat.pendingOutputAmount(chfYapealAsset)).toEqual(14980.12); + }); + + it('counts the output under the payout bank asset only', () => { + const buyFiat = createCustomBuyFiat({ + outputAmount: 100, + sell: createCustomSell({ fiat: createCustomFiat({ name: 'EUR' }) }), + fiatOutput: createCustomFiatOutput({ bank: olkyEUR, isTransmittedDate: new Date() }), + }); + + expect(buyFiat.pendingOutputAmount(eurOlkyAsset)).toEqual(100); + expect(buyFiat.pendingOutputAmount(chfYapealAsset)).toEqual(0); + }); + + it('defaults to Yapeal when no fiat output exists yet', () => { + const buyFiat = createCustomBuyFiat({ + outputAmount: 50, + sell: createCustomSell({ fiat: createCustomFiat({ name: 'CHF' }) }), + fiatOutput: undefined, + }); + + expect(buyFiat.pendingOutputAmount(chfYapealAsset)).toEqual(50); + expect(buyFiat.pendingOutputAmount(eurOlkyAsset)).toEqual(0); + }); + + it('returns 0 before the output amount is set', () => { + const buyFiat = createCustomBuyFiat({ + outputAmount: undefined, + sell: createCustomSell({ fiat: createCustomFiat({ name: 'CHF' }) }), + }); + + expect(buyFiat.pendingOutputAmount(chfYapealAsset)).toEqual(0); + }); + }); +}); diff --git a/src/subdomains/core/sell-crypto/process/buy-fiat.entity.ts b/src/subdomains/core/sell-crypto/process/buy-fiat.entity.ts index ecbbcc3005..73ce177b7f 100644 --- a/src/subdomains/core/sell-crypto/process/buy-fiat.entity.ts +++ b/src/subdomains/core/sell-crypto/process/buy-fiat.entity.ts @@ -557,8 +557,9 @@ export class BuyFiat extends IEntity { pendingOutputAmount(asset: Asset): number { const payoutBankName = this.fiatOutput?.bank?.name ?? IbanBankName.YAPEAL; - if (payoutBankName === IbanBankName.YAPEAL && this.fiatOutput?.isTransmittedDate) return 0; - + // the output stays a liability until the entity completes (outgoing bankTx booked): the bank + // balance only drops when the bank books the debit, which can be days after transmission + // (weekend/cut-off batches) - and a transmitted payment may still fail return this.outputAmount && asset.dexName === this.sell.fiat.name && asset.bank?.name === payoutBankName ? this.outputAmount : 0;