Compare commits

...
2 Commits
4 changed files with 65 additions and 5 deletions
@@ -210,11 +210,45 @@ describe('OrderService', () => {
accessToken: 'plain-token',
checkoutInvoice: expect.objectContaining({
statusLabel: 'Payment confirmed',
paymentLabel: 'XMR',
expectedTotalCrypto: '0.10000000'
})
})
);
});
it('formats bitcoin checkout invoice amounts for the admin order view', async () => {
const storedOrder = {
...buildStoredOrder(),
checkoutInvoice: {
id: 'invoice-1',
fiatCurrency: 'USD',
paymentMethod: PaymentMethod.Btc,
expectedTotalAtomic: '100000000',
expiresAt: new Date('2099-01-01T00:00:00.000Z'),
btcDetails: { fiatPerBtcAtCreation: 60_000, requiredConfirmations: 1 },
moneroDetails: null,
payments: [{ id: 'pay-1', amountAtomic: '100000000', confirmations: 1, txHash: 'tx-1' }],
reason: InvoiceReason.Checkout
}
} as unknown as Order;
orderDetailQueryBuilder.getOne.mockResolvedValue(storedOrder);
const result = await service.findById('order-1');
expect(result.checkoutInvoice).toEqual(
expect.objectContaining({
paymentLabel: 'BTC',
expectedTotalCrypto: '1.00000000',
payments: [
expect.objectContaining({
amountCrypto: '1.00000000'
})
]
})
);
});
});
describe('setDeliveryCost', () => {
@@ -8,7 +8,9 @@ import { formatInvoicePaymentConfirmationStatus } from '../../../utils/invoice/f
import { resolveInvoiceStatusMessage } from '../../../utils/invoice/resolveInvoiceStatusMessage';
import { resolveInvoiceRequiredConfirmations } from '../../../utils/invoice/resolveInvoiceRequiredConfirmations';
import type { InvoiceState } from '../../../utils/invoice/types/InvoiceState';
import { convertXmrAtomicToXmr } from '../../../utils/monero/convertXmrAtomicToXmr';
import type { CryptoAtomicConverter } from '../../../types/CryptoAtomicConverter';
import { paymentMethodLabel } from '../../../consts/paymentMethodLabel';
import { resolveAtomicToCryptoConverter } from '../../../utils/payment/resolveAtomicToCryptoConverter';
import type { Invoice } from '../../payment/entities/Invoice';
import type { InvoicePayment } from '../../payment/entities/InvoicePayment';
import type { InvoiceExtended } from '../../payment/types/InvoiceExtended';
@@ -182,24 +184,31 @@ export class OrderService {
const statusLabel = invoiceState ? resolveInvoiceStatusMessage(invoiceState) : null;
const expectedTotalCrypto = convertXmrAtomicToXmr(invoice.expectedTotalAtomic);
const convertAtomicToCrypto = resolveAtomicToCryptoConverter(invoice.paymentMethod);
const expectedTotalCrypto = convertAtomicToCrypto(invoice.expectedTotalAtomic);
const payments = (invoice.payments ?? []).map(payment =>
this.toInvoicePaymentExtended(payment, requiredConfirmations)
this.toInvoicePaymentExtended(payment, requiredConfirmations, convertAtomicToCrypto)
);
return {
...invoice,
statusLabel,
paymentLabel: paymentMethodLabel[invoice.paymentMethod],
expectedTotalCrypto,
payments
};
}
private toInvoicePaymentExtended(payment: InvoicePayment, requiredConfirmations: number): InvoicePaymentExtended {
private toInvoicePaymentExtended(
payment: InvoicePayment,
requiredConfirmations: number,
convertAtomicToCrypto: CryptoAtomicConverter
): InvoicePaymentExtended {
const isConfirmed = payment.confirmations >= requiredConfirmations;
const amountCrypto = convertXmrAtomicToXmr(payment.amountAtomic);
const amountCrypto = convertAtomicToCrypto(payment.amountAtomic);
const confirmationsLabel = formatInvoicePaymentConfirmationStatus({
confirmations: payment.confirmations,
@@ -4,6 +4,7 @@ import type { InvoiceStatusLabel } from '../../../utils/invoice/types/InvoiceSta
export type InvoiceExtended = Omit<Invoice, 'payments'> & {
statusLabel: InvoiceStatusLabel | null;
paymentLabel: string;
expectedTotalCrypto: string;
payments: InvoicePaymentExtended[];
};
@@ -0,0 +1,16 @@
import { InternalServerErrorException } from '@nestjs/common';
import { PaymentMethod } from '../../modules/payment/types/PaymentMethod';
import type { CryptoAtomicConverter } from '../../types/CryptoAtomicConverter';
import { convertBtcAtomicToBtc } from '../bitcoin/convertBtcAtomicToBtc';
import { convertXmrAtomicToXmr } from '../monero/convertXmrAtomicToXmr';
export const resolveAtomicToCryptoConverter = (paymentMethod: PaymentMethod): CryptoAtomicConverter => {
switch (paymentMethod) {
case PaymentMethod.Xmr:
return convertXmrAtomicToXmr;
case PaymentMethod.Btc:
return convertBtcAtomicToBtc;
default:
throw new InternalServerErrorException(`Unsupported payment method: ${String(paymentMethod)}`);
}
};