feat: add shipping fee resolution to invoice items and refactor item building logic
This commit is contained in:
parent
bd21801c41
commit
b87b999455
@ -12,6 +12,7 @@ const fs = require('fs/promises');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const CompanySettingsRepository = require('../../repositories/settings/CompanySettingsRepository');
|
const CompanySettingsRepository = require('../../repositories/settings/CompanySettingsRepository');
|
||||||
|
const CoffeeShippingFeeService = require('../subscriptions/CoffeeShippingFeeService');
|
||||||
|
|
||||||
class InvoiceService {
|
class InvoiceService {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -58,6 +59,54 @@ class InvoiceService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _resolveShippingFeeItem({ abonement, vatRate, lang }) {
|
||||||
|
const pieceCount = this._resolvePieceCountForQr(abonement);
|
||||||
|
if (!pieceCount) return null;
|
||||||
|
|
||||||
|
const shippingFee = await CoffeeShippingFeeService.get(pieceCount);
|
||||||
|
const unitPrice = Number(shippingFee?.price || 0);
|
||||||
|
if (!(unitPrice > 0)) return null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
product_id: null,
|
||||||
|
sku: `SHIPPING-${pieceCount}`,
|
||||||
|
description: lang === 'de' ? `Versandkosten (${pieceCount} Stk.)` : `Shipping fee (${pieceCount} pcs)` ,
|
||||||
|
quantity: 1,
|
||||||
|
unit_price: unitPrice,
|
||||||
|
tax_rate: vatRate,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async _buildInvoiceItems({ abonement, vatRate, lang }) {
|
||||||
|
const breakdown = Array.isArray(abonement?.pack_breakdown) ? abonement.pack_breakdown : [];
|
||||||
|
const items = breakdown.length
|
||||||
|
? breakdown.map((b) => ({
|
||||||
|
product_id: Number(b.coffee_table_id) || null,
|
||||||
|
sku: `COFFEE-${b.coffee_table_id || 'N/A'}`,
|
||||||
|
description: b.coffee_title || `Coffee subscription: ${b.coffee_table_id}`,
|
||||||
|
quantity: Number(b.packs || 1),
|
||||||
|
unit_price: Number(b.price_per_pack || 0),
|
||||||
|
tax_rate: b.tax_rate != null ? Number(b.tax_rate) : vatRate,
|
||||||
|
}))
|
||||||
|
: [
|
||||||
|
{
|
||||||
|
product_id: null,
|
||||||
|
sku: 'SUBSCRIPTION',
|
||||||
|
description: `Subscription ${abonement?.pack_group || ''}`,
|
||||||
|
quantity: 1,
|
||||||
|
unit_price: Number(abonement?.price || 0),
|
||||||
|
tax_rate: vatRate,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const shippingItem = await this._resolveShippingFeeItem({ abonement, vatRate, lang });
|
||||||
|
if (shippingItem) {
|
||||||
|
items.push(shippingItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
async _getCompanySettingsQrDataUri(pieceCount) {
|
async _getCompanySettingsQrDataUri(pieceCount) {
|
||||||
const safePieceCount = pieceCount === 120 ? 120 : 60;
|
const safePieceCount = pieceCount === 120 ? 120 : 60;
|
||||||
try {
|
try {
|
||||||
@ -598,26 +647,7 @@ class InvoiceService {
|
|||||||
// NEW: resolve invoice vat_rate (standard) from buyer country
|
// NEW: resolve invoice vat_rate (standard) from buyer country
|
||||||
const vat_rate = await this.resolveVatRateForCountry(addr.country);
|
const vat_rate = await this.resolveVatRateForCountry(addr.country);
|
||||||
|
|
||||||
const breakdown = Array.isArray(abonement.pack_breakdown) ? abonement.pack_breakdown : [];
|
const items = await this._buildInvoiceItems({ abonement, vatRate: vat_rate, lang });
|
||||||
const items = breakdown.length
|
|
||||||
? breakdown.map((b) => ({
|
|
||||||
product_id: Number(b.coffee_table_id) || null,
|
|
||||||
sku: `COFFEE-${b.coffee_table_id || 'N/A'}`,
|
|
||||||
description: b.coffee_title || `Coffee subscription: ${b.coffee_table_id}`,
|
|
||||||
quantity: Number(b.packs || 1),
|
|
||||||
unit_price: Number(b.price_per_pack || 0),
|
|
||||||
tax_rate: b.tax_rate != null ? Number(b.tax_rate) : vat_rate, // CHANGED: default to invoice vat_rate
|
|
||||||
}))
|
|
||||||
: [
|
|
||||||
{
|
|
||||||
product_id: null,
|
|
||||||
sku: 'SUBSCRIPTION',
|
|
||||||
description: `Subscription ${abonement.pack_group || ''}`,
|
|
||||||
quantity: 1,
|
|
||||||
unit_price: Number(abonement.price || 0),
|
|
||||||
tax_rate: vat_rate, // CHANGED
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const context = {
|
const context = {
|
||||||
source: 'abonement',
|
source: 'abonement',
|
||||||
@ -677,6 +707,9 @@ class InvoiceService {
|
|||||||
logger.error('InvoiceService.issueForAbonement:invoice_email_error', {
|
logger.error('InvoiceService.issueForAbonement:invoice_email_error', {
|
||||||
invoiceId: invoice?.id,
|
invoiceId: invoice?.id,
|
||||||
message: mailError?.message,
|
message: mailError?.message,
|
||||||
|
stack: mailError?.stack,
|
||||||
|
brevoStatus: mailError?.statusCode ?? mailError?.response?.status ?? null,
|
||||||
|
brevoData: mailError?.body ?? mailError?.response?.data ?? mailError?.response?.text ?? null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user