Fixed extensions bugs

This commit is contained in:
Emil
2026-02-24 16:06:36 +01:00
parent 0764bc11a6
commit e0b66fe397
26 changed files with 3394 additions and 167 deletions
@@ -12,7 +12,7 @@
* Deadline: 25th of the month following the reporting period
*/
import { isEUCountry } from '@/extensions/export/shared/eu-countries'
import { isEUCountry, toCountryCode } from '@/extensions/export/shared/eu-countries'
// ── Types ────────────────────────────────────────────────────
@@ -231,6 +231,9 @@ export function generateECSalesListReport(options: GenerateReportOptions): ECSal
// Classify: goods (box 35) or services (box 39)
const classification = classifyInvoice(invoice)
// Normalize country to ISO code for consistent output
const countryCode = toCountryCode(customer.country)
// Get or create aggregation line
const vatNumber = customer.vat_number
const key = vatNumber
@@ -238,7 +241,7 @@ export function generateECSalesListReport(options: GenerateReportOptions): ECSal
aggregation.set(key, {
customerVatNumber: vatNumber,
customerName: customer.name,
customerCountry: customer.country,
customerCountry: countryCode,
customerId: customer.id,
goodsAmount: 0,
servicesAmount: 0,
@@ -15,7 +15,7 @@
* Reference: SCB Intrastat guidelines, Combined Nomenclature (CN)
*/
import { isEUCountry } from '@/extensions/export/shared/eu-countries'
import { isEUCountry, toCountryCode } from '@/extensions/export/shared/eu-countries'
// ── Types ────────────────────────────────────────────────────
@@ -192,6 +192,7 @@ export function generateIntrastatReport(options: IntrastatOptions): IntrastatRep
for (const invoice of relevantInvoices) {
const customer = customerMap.get(invoice.customer_id)!
const partnerCountryCode = toCountryCode(customer.country)
const isCreditNote = invoice.credited_invoice_id !== null
const items = itemsByInvoice.get(invoice.id) ?? []
@@ -208,10 +209,10 @@ export function generateIntrastatReport(options: IntrastatOptions): IntrastatRep
message: `Faktura ${invoice.invoice_number} saknar fakturarader — kan inte tilldela CN-kod.`,
})
const key = buildAggKey('00000000', customer.country, 'SE', defaultTransactionNature, defaultDeliveryTerms)
const key = buildAggKey('00000000', partnerCountryCode, 'SE', defaultTransactionNature, defaultDeliveryTerms)
addToAggregation(aggregation, key, {
cnCode: '00000000',
partnerCountry: customer.country,
partnerCountry: partnerCountryCode,
countryOfOrigin: 'SE',
transactionNature: defaultTransactionNature,
deliveryTerms: defaultDeliveryTerms,
@@ -240,10 +241,10 @@ export function generateIntrastatReport(options: IntrastatOptions): IntrastatRep
message: `Faktura ${invoice.invoice_number}, rad "${item.description}" — ingen matchande produkt med CN-kod hittad.`,
})
const key = buildAggKey('00000000', customer.country, 'SE', defaultTransactionNature, defaultDeliveryTerms)
const key = buildAggKey('00000000', partnerCountryCode, 'SE', defaultTransactionNature, defaultDeliveryTerms)
addToAggregation(aggregation, key, {
cnCode: '00000000',
partnerCountry: customer.country,
partnerCountry: partnerCountryCode,
countryOfOrigin: 'SE',
transactionNature: defaultTransactionNature,
deliveryTerms: defaultDeliveryTerms,
@@ -286,10 +287,10 @@ export function generateIntrastatReport(options: IntrastatOptions): IntrastatRep
? product.supplementaryUnit * item.quantity
: null
const key = buildAggKey(cnCode, customer.country, origin, defaultTransactionNature, defaultDeliveryTerms)
const key = buildAggKey(cnCode, partnerCountryCode, origin, defaultTransactionNature, defaultDeliveryTerms)
addToAggregation(aggregation, key, {
cnCode,
partnerCountry: customer.country,
partnerCountry: partnerCountryCode,
countryOfOrigin: origin,
transactionNature: defaultTransactionNature,
deliveryTerms: defaultDeliveryTerms,
+43 -9
View File
@@ -58,22 +58,56 @@ export const EU_COUNTRY_CODES_EXCL_SE = EU_COUNTRIES
/** All EU country codes including Sweden */
export const EU_COUNTRY_CODES = EU_COUNTRIES.map(c => c.code)
/** Check if a country code is an EU member state (excluding Sweden) */
export function isEUCountry(countryCode: string): boolean {
return EU_COUNTRY_CODES_EXCL_SE.includes(countryCode.toUpperCase())
/**
* Build a lookup set of all known names/codes for EU countries (excluding Sweden).
* Handles ISO codes, English names, and Swedish names — all uppercased for matching.
*/
const EU_LOOKUP_EXCL_SE = new Set(
EU_COUNTRIES
.filter(c => c.code !== 'SE')
.flatMap(c => [c.code, c.name, c.nameEn].map(s => s.toUpperCase()))
)
const EU_LOOKUP_INCL_SE = new Set(
EU_COUNTRIES
.flatMap(c => [c.code, c.name, c.nameEn].map(s => s.toUpperCase()))
)
/**
* Check if a country value is an EU member state (excluding Sweden).
* Accepts ISO codes ("DE"), English names ("Germany"), or Swedish names ("Tyskland").
*/
export function isEUCountry(country: string): boolean {
return EU_LOOKUP_EXCL_SE.has(country.trim().toUpperCase())
}
/** Check if a country code is an EU member state (including Sweden) */
export function isEUCountryIncludingSE(countryCode: string): boolean {
return EU_COUNTRY_CODES.includes(countryCode.toUpperCase())
/**
* Check if a country value is an EU member state (including Sweden).
* Accepts ISO codes, English names, or Swedish names.
*/
export function isEUCountryIncludingSE(country: string): boolean {
return EU_LOOKUP_INCL_SE.has(country.trim().toUpperCase())
}
/** Get EU country data by ISO code */
export function getEUCountry(countryCode: string): EUCountry | undefined {
return EU_COUNTRIES.find(c => c.code === countryCode.toUpperCase())
/** Get EU country data by ISO code, English name, or Swedish name */
export function getEUCountry(country: string): EUCountry | undefined {
const upper = country.trim().toUpperCase()
return EU_COUNTRIES.find(
c => c.code === upper || c.name.toUpperCase() === upper || c.nameEn.toUpperCase() === upper
)
}
/** Get the VIES VAT prefix for a country (note: Greece uses 'EL' not 'GR') */
export function getVatPrefix(countryCode: string): string | undefined {
return getEUCountry(countryCode)?.vatPrefix
}
/**
* Normalize a country value to its ISO 3166-1 alpha-2 code.
* Accepts ISO codes, English names, or Swedish names.
* Returns the input uppercased if no match is found.
*/
export function toCountryCode(country: string): string {
const found = getEUCountry(country)
return found ? found.code : country.trim().toUpperCase()
}