feat(report): Kundennummer an DOCUframe-Makro _SV_assignDeliveryReport uebergeben
Das Makro ordnet den Lieferbericht dem Vorgang des Kunden zu und braucht
dafuer jetzt zusaetzlich die im ERP hinterlegte Kundennummer:
{ objectId, belegnummer, kundennummer }
- AssignReportRequest + Gateway-Port um kundennummer (String) erweitert
- AttachmentRepository.delivery_customer_number(): liest
customers.erp_customer_id (= ERP Kunden.Kundennummer) ueber
deliveries.customer_id
- ProcessDeliveryReportUseCase liest die Nummer aus der DB (nicht aus dem
Render-Ergebnis), damit sie auch im Retry-Pfad ohne erneutes Rendern vorliegt
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -58,6 +58,15 @@ pub trait AttachmentRepository: Send + Sync {
|
|||||||
delivery_id: Uuid,
|
delivery_id: Uuid,
|
||||||
) -> Result<Option<String>, ApplicationError>;
|
) -> Result<Option<String>, ApplicationError>;
|
||||||
|
|
||||||
|
/// Liefert die ERP-Kundennummer (`customers.erp_customer_id`) des Kunden
|
||||||
|
/// der Lieferung. Wird u. a. dem DOCUframe-Makro
|
||||||
|
/// `_SV_assignDeliveryReport` als `kundennummer` mitgegeben. `None`, wenn
|
||||||
|
/// die Lieferung nicht (mehr) existiert.
|
||||||
|
async fn delivery_customer_number(
|
||||||
|
&self,
|
||||||
|
delivery_id: Uuid,
|
||||||
|
) -> Result<Option<i64>, ApplicationError>;
|
||||||
|
|
||||||
/// Listet alle noch nicht gelöschten Attachments einer Lieferung
|
/// Listet alle noch nicht gelöschten Attachments einer Lieferung
|
||||||
/// (`deleted_at IS NULL`) mit ihrer lokalen Referenz — fürs Aufräumen.
|
/// (`deleted_at IS NULL`) mit ihrer lokalen Referenz — fürs Aufräumen.
|
||||||
async fn list_active_for_delivery(
|
async fn list_active_for_delivery(
|
||||||
|
|||||||
@ -22,12 +22,15 @@ pub trait DocuframeReportGateway: Send + Sync {
|
|||||||
pdf: Vec<u8>,
|
pdf: Vec<u8>,
|
||||||
) -> Result<String, ApplicationError>;
|
) -> Result<String, ApplicationError>;
|
||||||
|
|
||||||
/// Ruft das Makro `_SV_assignDeliveryReport` mit `{objectId, belegnummer}`
|
/// Ruft das Makro `_SV_assignDeliveryReport` mit
|
||||||
/// auf und ordnet den hochgeladenen Report dem Beleg zu. Fehler, wenn das
|
/// `{objectId, belegnummer, kundennummer}` auf und ordnet den hochgeladenen
|
||||||
/// Makro `succeeded != true` liefert oder DOCUframe nicht erreichbar ist.
|
/// Report dem Beleg bzw. dem Vorgang des Kunden zu. `kundennummer` ist die
|
||||||
|
/// im ERP hinterlegte Kundennummer (als String). Fehler, wenn das Makro
|
||||||
|
/// `succeeded != true` liefert oder DOCUframe nicht erreichbar ist.
|
||||||
async fn assign_report(
|
async fn assign_report(
|
||||||
&self,
|
&self,
|
||||||
object_id: &str,
|
object_id: &str,
|
||||||
belegnummer: &str,
|
belegnummer: &str,
|
||||||
|
kundennummer: &str,
|
||||||
) -> Result<(), ApplicationError>;
|
) -> Result<(), ApplicationError>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -92,8 +92,20 @@ impl ProcessDeliveryReportUseCase {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Schritt 3: Makro-Zuordnung (muss succeeded == true liefern).
|
// Schritt 3: Makro-Zuordnung (muss succeeded == true liefern). Das
|
||||||
self.gateway.assign_report(&object_id, &belegnummer).await?;
|
// Makro braucht zusätzlich die ERP-Kundennummer, um den Report dem
|
||||||
|
// Vorgang des Kunden zuzuordnen. Bewusst aus der DB gelesen (nicht aus
|
||||||
|
// dem Render-Ergebnis), damit sie auch im Retry-Pfad vorliegt, in dem
|
||||||
|
// das Rendern übersprungen wird.
|
||||||
|
let kundennummer = self
|
||||||
|
.attachment_repo
|
||||||
|
.delivery_customer_number(delivery_id)
|
||||||
|
.await?
|
||||||
|
.ok_or(ApplicationError::NotFound)?
|
||||||
|
.to_string();
|
||||||
|
self.gateway
|
||||||
|
.assign_report(&object_id, &belegnummer, &kundennummer)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// Schritt 4: erst aufräumen, dann als erledigt markieren.
|
// Schritt 4: erst aufräumen, dann als erledigt markieren.
|
||||||
self.cleanup_local(delivery_id, &belegnummer).await;
|
self.cleanup_local(delivery_id, &belegnummer).await;
|
||||||
|
|||||||
@ -92,9 +92,15 @@ pub struct CommitData {
|
|||||||
// ─── Makro-Aufruf (`/v1/execute/<name>`) ────────────────────────────────────
|
// ─── Makro-Aufruf (`/v1/execute/<name>`) ────────────────────────────────────
|
||||||
|
|
||||||
/// Request-Body für das Makro `_SV_assignDeliveryReport`.
|
/// Request-Body für das Makro `_SV_assignDeliveryReport`.
|
||||||
|
///
|
||||||
|
/// Beispiel: `{ "objectId": "1EBGJM", "belegnummer": "V-30690285",
|
||||||
|
/// "kundennummer": "123456" }`.
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub struct AssignReportRequest<'a> {
|
pub struct AssignReportRequest<'a> {
|
||||||
#[serde(rename = "objectId")]
|
#[serde(rename = "objectId")]
|
||||||
pub object_id: &'a str,
|
pub object_id: &'a str,
|
||||||
pub belegnummer: &'a str,
|
pub belegnummer: &'a str,
|
||||||
|
/// Im ERP hinterlegte Kundennummer des Kunden (String, wie vom Makro
|
||||||
|
/// erwartet) — damit DOCUframe den Report dem Vorgang des Kunden zuordnet.
|
||||||
|
pub kundennummer: &'a str,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -497,10 +497,12 @@ impl DocuframeReportGateway for GsdService {
|
|||||||
&self,
|
&self,
|
||||||
object_id: &str,
|
object_id: &str,
|
||||||
belegnummer: &str,
|
belegnummer: &str,
|
||||||
|
kundennummer: &str,
|
||||||
) -> Result<(), ApplicationError> {
|
) -> Result<(), ApplicationError> {
|
||||||
let body = serde_json::to_value(super::dto::AssignReportRequest {
|
let body = serde_json::to_value(super::dto::AssignReportRequest {
|
||||||
object_id,
|
object_id,
|
||||||
belegnummer,
|
belegnummer,
|
||||||
|
kundennummer,
|
||||||
})
|
})
|
||||||
.map_err(Self::ext)?;
|
.map_err(Self::ext)?;
|
||||||
let val = self
|
let val = self
|
||||||
|
|||||||
@ -78,6 +78,23 @@ impl AttachmentRepository for PgAttachmentRepository {
|
|||||||
Ok(belegnummer)
|
Ok(belegnummer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn delivery_customer_number(
|
||||||
|
&self,
|
||||||
|
delivery_id: Uuid,
|
||||||
|
) -> Result<Option<i64>, ApplicationError> {
|
||||||
|
let customer_number: Option<i64> = sqlx::query_scalar(
|
||||||
|
"SELECT c.erp_customer_id \
|
||||||
|
FROM deliveries d \
|
||||||
|
JOIN customers c ON c.id = d.customer_id \
|
||||||
|
WHERE d.id = $1",
|
||||||
|
)
|
||||||
|
.bind(delivery_id)
|
||||||
|
.fetch_optional(&self.pool)
|
||||||
|
.await
|
||||||
|
.map_err(db)?;
|
||||||
|
Ok(customer_number)
|
||||||
|
}
|
||||||
|
|
||||||
async fn list_active_for_delivery(
|
async fn list_active_for_delivery(
|
||||||
&self,
|
&self,
|
||||||
delivery_id: Uuid,
|
delivery_id: Uuid,
|
||||||
|
|||||||
Reference in New Issue
Block a user