import { Injectable } from '@nestjs/common';
import { DatabaseService } from '../../../infrastructure/database/database.service';
import { DomainConflictError } from '../../../common/errors/domain-conflict.error';
import { ExternalConflictService } from './external-conflict.service';
@Injectable()
export class SupplierGoodsReceiptService {
constructor(
private readonly database:DatabaseService,
private readonly conflicts:ExternalConflictService,
) {}
async commit(input:{organizationId:string;locationId:string;importId:string}) {
return this.database.transaction(async(tx)=>{
const rows=await tx.query<any>(
`select * from supplier_goods_receipt_imports
where id=$1 and organization_id=$2 and location_id=$3
and status='received'
for update`,
[input.importId,input.organizationId,input.locationId],
);
const job=rows[0];
if(!job) throw new DomainConflictError('supplier.goods_receipt_invalid');
const items=job.payload_json?.items;
if(!Array.isArray(items) || items.length===0) {
throw new DomainConflictError('supplier.goods_receipt_no_items');
}
let accepted=0;
for(const item of items) {
const mapping=await tx.query<any>(
`select local_entity_id
from external_system_mappings
where integration_connection_id=$1
and external_entity_type='supplier_product'
and external_id=$2 and status='active'
and (location_id is null or location_id=$3)`,
[job.integration_connection_id,item.externalSupplierProductId,input.locationId],
);
if(!mapping[0]?.local_entity_id) {
await this.conflicts.create({
organizationId:input.organizationId,locationId:input.locationId,
connectionId:job.integration_connection_id,
conflictType:'supplier_mapping_missing',
severity:'high',externalEntityType:'supplier_product',
externalId:item.externalSupplierProductId,
externalSnapshot:item,summary:'Goods receipt item has no supplier-product mapping.',
});
continue;
}
// Keep the imported receipt durable without guessing inventory unit semantics.
// Canonical StockMovement application needs explicit normalized quantity/unit mapping.
accepted++;
}
const status=accepted===items.length?'completed':'conflict';
await tx.query(
`update supplier_goods_receipt_imports
set status=$1,completed_at=case when $1='completed' then now() else null end
where id=$2`,
[status,job.id],
);
return {id:job.id,status,accepted,total:items.length};
});
}
}
