// workflows/amazon/helpers/amazon-batch-processing.ts
export interface AmazonBatchProcessingResult {
processedCount: number;
duplicateCount: number;
failedCount: number;
createdDocumentIds: string[];
}
/**
* Process Amazon documents through the standard pipeline.
* Mirrors PayPal's processPaypalDocumentsBatch for consistency.
*/
export async function processAmazonDocumentsBatch(
orders: ParsedVATTaxOrder[],
config: AmazonDocumentTypeConfig,
resources: AmazonOrderResources,
organizationId: string,
activities: AmazonBatchProcessingActivities
): Promise<AmazonBatchProcessingResult> {
// Step 1: Filter by document type
const filteredOrders = config.filterOrders(orders);
if (filteredOrders.length === 0) {
return { processedCount: 0, duplicateCount: 0, failedCount: 0, createdDocumentIds: [] };
}
// Step 2: Duplicate check
const transactionIds = filteredOrders.map((o) => o.eventId);
const dupCheck = await activities.batchFindExistingDocumentsActivity({
customPropertyIds: transactionIds,
organizationId,
objectTypeId: resources.objectTypes[config.objectTypeKey].id,
customIdField: config.customIdField,
});
const newOrders = filteredOrders.filter((o) => dupCheck.newCustomPropertyIds.includes(o.eventId));
const duplicateCount = filteredOrders.length - newOrders.length;
if (newOrders.length === 0) {
return { processedCount: 0, duplicateCount, failedCount: 0, createdDocumentIds: [] };
}
// Step 3: Process customers
const customerInputs = prepareCustomerInputs(newOrders, config);
const customerResult =
customerInputs.length > 0
? await activities.batchProcessCustomersActivity({
customers: customerInputs,
organizationId,
objectTypeId: resources.objectTypes.customer.id,
modifiedByActorId: resources.actor.id,
customIdField: config.type === "invoice" ? "amazon_order_id" : "amazon_refund_id",
})
: { customerMap: {}, customersProcessed: 0 };
// Step 4: Process addresses
const addressInputs = prepareAddressInputs(newOrders, customerResult.customerMap, config);
const addressResult =
addressInputs.length > 0
? await activities.batchProcessAddressesActivity({
addresses: addressInputs,
organizationId,
modifiedByActorId: resources.actor.id,
updateEntityDefaultAddresses: true,
})
: { addressMap: {}, addressesProcessed: 0 };
// Step 5: Allocate numbers and periods
const docsToCreate = prepareDocumentsForProcessing(newOrders, config, resources);
const [numberResult, periodResult] = await Promise.all([
activities.batchAllocateNumbersActivity({ documentsToCreate: docsToCreate, organizationId }),
activities.batchProcessAccountingPeriodsActivity({
documentsToCreate: docsToCreate,
organizationId,
}),
]);
// Step 6: Create documents
const documents = createDocuments(
newOrders,
config,
resources,
periodResult,
customerResult.customerMap,
addressResult.addressMap
);
const documentsWithNumbers = attachAllocatedNumbers(documents, numberResult, config, resources);
const createResult = await createDocumentsInBatches(
documentsWithNumbers,
organizationId,
config,
periodResult,
addressResult,
resources,
activities
);
// Step 7: Enqueue accounting jobs
if (createResult.documentIds.length > 0) {
await enqueueAccountingJobsInBatches(
createResult.documentIds,
organizationId,
config.accountingJobType,
activities
);
}
return {
processedCount: createResult.documentIds.length,
duplicateCount,
failedCount: createResult.failedDocuments?.length || 0,
createdDocumentIds: createResult.documentIds,
};
}