From da4294791e861b89b4b976b459b739eb0920a7a7 Mon Sep 17 00:00:00 2001 From: Carlos Feria <2582866+carlosthe19916@users.noreply.github.com> Date: Mon, 2 Mar 2026 22:33:43 +0100 Subject: [PATCH 1/3] feat: add invoice attributos Signed-off-by: Carlos Feria <2582866+carlosthe19916@users.noreply.github.com> --- xbuilder/tests/credit_note_atributos.rs | 43 ++++++ xbuilder/tests/debit_note_atributos.rs | 43 ++++++ xbuilder/tests/invoice_atributos.rs | 79 ++++++++++ .../atributosSimple.xml | 138 +++++++++++++++++ .../atributosSimple.xml | 138 +++++++++++++++++ .../atributosConPeriodo.xml | 139 ++++++++++++++++++ .../InvoiceAtributosTest/atributosSimple.xml | 134 +++++++++++++++++ 7 files changed, 714 insertions(+) create mode 100644 xbuilder/tests/credit_note_atributos.rs create mode 100644 xbuilder/tests/debit_note_atributos.rs create mode 100644 xbuilder/tests/invoice_atributos.rs create mode 100644 xbuilder/tests/resources/e2e/renderer/creditnote/CreditNoteAtributosTest/atributosSimple.xml create mode 100644 xbuilder/tests/resources/e2e/renderer/debitnote/DebitNoteAtributosTest/atributosSimple.xml create mode 100644 xbuilder/tests/resources/e2e/renderer/invoice/InvoiceAtributosTest/atributosConPeriodo.xml create mode 100644 xbuilder/tests/resources/e2e/renderer/invoice/InvoiceAtributosTest/atributosSimple.xml diff --git a/xbuilder/tests/credit_note_atributos.rs b/xbuilder/tests/credit_note_atributos.rs new file mode 100644 index 00000000..cd90d9e2 --- /dev/null +++ b/xbuilder/tests/credit_note_atributos.rs @@ -0,0 +1,43 @@ +use rust_decimal_macros::dec; + +use xbuilder::prelude::*; + +use crate::common::{assert_credit_note, credit_note_base}; + +mod common; + +const BASE: &str = "tests/resources/e2e/renderer/creditnote/CreditNoteAtributosTest"; + +#[serial_test::serial] +#[tokio::test] +async fn credit_note_with_atributos() { + let mut credit_note = CreditNote { + detalles: vec![Detalle { + descripcion: "Item1", + cantidad: dec!(10), + precio: Some(dec!(100)), + atributos: vec![ + Atributo { + nombre: "Marca", + codigo: "BRA", + valor: Some("Samsung"), + fecha_inicio: None, + fecha_fin: None, + duracion: None, + }, + Atributo { + nombre: "Color", + codigo: "COL", + valor: Some("Negro"), + fecha_inicio: None, + fecha_fin: None, + duracion: None, + }, + ], + ..Default::default() + }], + ..credit_note_base() + }; + + assert_credit_note(&mut credit_note, &format!("{BASE}/atributosSimple.xml")).await; +} diff --git a/xbuilder/tests/debit_note_atributos.rs b/xbuilder/tests/debit_note_atributos.rs new file mode 100644 index 00000000..6dbd880e --- /dev/null +++ b/xbuilder/tests/debit_note_atributos.rs @@ -0,0 +1,43 @@ +use rust_decimal_macros::dec; + +use xbuilder::prelude::*; + +use crate::common::{assert_debit_note, debit_note_base}; + +mod common; + +const BASE: &str = "tests/resources/e2e/renderer/debitnote/DebitNoteAtributosTest"; + +#[serial_test::serial] +#[tokio::test] +async fn debit_note_with_atributos() { + let mut debit_note = DebitNote { + detalles: vec![Detalle { + descripcion: "Item1", + cantidad: dec!(10), + precio: Some(dec!(100)), + atributos: vec![ + Atributo { + nombre: "Marca", + codigo: "BRA", + valor: Some("Samsung"), + fecha_inicio: None, + fecha_fin: None, + duracion: None, + }, + Atributo { + nombre: "Color", + codigo: "COL", + valor: Some("Negro"), + fecha_inicio: None, + fecha_fin: None, + duracion: None, + }, + ], + ..Default::default() + }], + ..debit_note_base() + }; + + assert_debit_note(&mut debit_note, &format!("{BASE}/atributosSimple.xml")).await; +} diff --git a/xbuilder/tests/invoice_atributos.rs b/xbuilder/tests/invoice_atributos.rs new file mode 100644 index 00000000..41cdf502 --- /dev/null +++ b/xbuilder/tests/invoice_atributos.rs @@ -0,0 +1,79 @@ +use chrono::NaiveDate; +use rust_decimal_macros::dec; + +use xbuilder::prelude::*; + +use crate::common::assert_invoice; +use crate::common::invoice_base; + +mod common; + +const BASE: &str = "tests/resources/e2e/renderer/invoice/InvoiceAtributosTest"; + +#[serial_test::serial] +#[tokio::test] +async fn invoice_with_atributos_simple() { + let mut invoice = Invoice { + detalles: vec![Detalle { + descripcion: "Item1", + cantidad: dec!(2), + precio: Some(dec!(100)), + atributos: vec![ + Atributo { + nombre: "Marca", + codigo: "BRA", + valor: Some("Samsung"), + fecha_inicio: None, + fecha_fin: None, + duracion: None, + }, + Atributo { + nombre: "Color", + codigo: "COL", + valor: Some("Negro"), + fecha_inicio: None, + fecha_fin: None, + duracion: None, + }, + ], + ..Default::default() + }], + ..invoice_base() + }; + + assert_invoice(&mut invoice, &format!("{BASE}/atributosSimple.xml")).await; +} + +#[serial_test::serial] +#[tokio::test] +async fn invoice_with_atributos_con_periodo() { + let mut invoice = Invoice { + detalles: vec![Detalle { + descripcion: "Item1", + cantidad: dec!(2), + precio: Some(dec!(100)), + atributos: vec![ + Atributo { + nombre: "Garantia", + codigo: "WAR", + valor: Some("12 meses"), + fecha_inicio: Some(NaiveDate::from_ymd_opt(2019, 12, 24).unwrap()), + fecha_fin: Some(NaiveDate::from_ymd_opt(2020, 12, 24).unwrap()), + duracion: Some(365), + }, + Atributo { + nombre: "Modelo", + codigo: "MOD", + valor: Some("Galaxy S10"), + fecha_inicio: None, + fecha_fin: None, + duracion: None, + }, + ], + ..Default::default() + }], + ..invoice_base() + }; + + assert_invoice(&mut invoice, &format!("{BASE}/atributosConPeriodo.xml")).await; +} diff --git a/xbuilder/tests/resources/e2e/renderer/creditnote/CreditNoteAtributosTest/atributosSimple.xml b/xbuilder/tests/resources/e2e/renderer/creditnote/CreditNoteAtributosTest/atributosSimple.xml new file mode 100644 index 00000000..5b7f1d87 --- /dev/null +++ b/xbuilder/tests/resources/e2e/renderer/creditnote/CreditNoteAtributosTest/atributosSimple.xml @@ -0,0 +1,138 @@ + + + + + + + + 2.1 + 2.0 + FC01-1 + 2019-12-24 + PEN + + F001-1 + 01 + + + + + F001-1 + 01 + + + + 12345678912 + + + 12345678912 + + + + + + + + #PROJECT-OPENUBL-SIGN + + + + + + + 12345678912 + + + + + 0000 + + + + + + + + 12121212121 + + + + + + + + 180.00 + + 1000.00 + 180.00 + + S + + 1000 + IGV + VAT + + + + + + 1000.00 + 1180.00 + 1180.00 + + + 1 + 10 + 1000.00 + + + 118.00 + 01 + + + + 180.00 + + 1000.00 + 180.00 + + S + 18.00 + 10 + + 1000 + IGV + VAT + + + + + + + + Marca + BRA + Samsung + + + Color + COL + Negro + + + + 100.00 + + + diff --git a/xbuilder/tests/resources/e2e/renderer/debitnote/DebitNoteAtributosTest/atributosSimple.xml b/xbuilder/tests/resources/e2e/renderer/debitnote/DebitNoteAtributosTest/atributosSimple.xml new file mode 100644 index 00000000..56ea7741 --- /dev/null +++ b/xbuilder/tests/resources/e2e/renderer/debitnote/DebitNoteAtributosTest/atributosSimple.xml @@ -0,0 +1,138 @@ + + + + + + + + 2.1 + 2.0 + FD01-1 + 2019-12-24 + PEN + + F001-1 + 01 + + + + + F001-1 + 01 + + + + 12345678912 + + + 12345678912 + + + + + + + + #PROJECT-OPENUBL-SIGN + + + + + + + 12345678912 + + + + + 0000 + + + + + + + + 12121212121 + + + + + + + + 180.00 + + 1000.00 + 180.00 + + S + + 1000 + IGV + VAT + + + + + + 1000.00 + 1180.00 + 1180.00 + + + 1 + 10 + 1000.00 + + + 118.00 + 01 + + + + 180.00 + + 1000.00 + 180.00 + + S + 18.00 + 10 + + 1000 + IGV + VAT + + + + + + + + Marca + BRA + Samsung + + + Color + COL + Negro + + + + 100.00 + + + diff --git a/xbuilder/tests/resources/e2e/renderer/invoice/InvoiceAtributosTest/atributosConPeriodo.xml b/xbuilder/tests/resources/e2e/renderer/invoice/InvoiceAtributosTest/atributosConPeriodo.xml new file mode 100644 index 00000000..4cf5cf0e --- /dev/null +++ b/xbuilder/tests/resources/e2e/renderer/invoice/InvoiceAtributosTest/atributosConPeriodo.xml @@ -0,0 +1,139 @@ + + + + + + + + 2.1 + 2.0 + F001-1 + 2019-12-24 + 01 + PEN + + 12345678912 + + + 12345678912 + + + + + + + + #PROJECT-OPENUBL-SIGN + + + + + + + 12345678912 + + + + + 0000 + + + + + + + + 12121212121 + + + + + + + + FormaPago + Contado + + + 36.00 + + 200.00 + 36.00 + + S + + 1000 + IGV + VAT + + + + + + 200.00 + 236.00 + 0 + 0 + 236.00 + + + 1 + 2 + 200.00 + + + 118.00 + 01 + + + + 36.00 + + 200.00 + 36.00 + + S + 18.00 + 10 + + 1000 + IGV + VAT + + + + + + + + Garantia + WAR + 12 meses + + 2019-12-24 + 2020-12-24 + 365 + + + + Modelo + MOD + Galaxy S10 + + + + 100.00 + + + diff --git a/xbuilder/tests/resources/e2e/renderer/invoice/InvoiceAtributosTest/atributosSimple.xml b/xbuilder/tests/resources/e2e/renderer/invoice/InvoiceAtributosTest/atributosSimple.xml new file mode 100644 index 00000000..4408001d --- /dev/null +++ b/xbuilder/tests/resources/e2e/renderer/invoice/InvoiceAtributosTest/atributosSimple.xml @@ -0,0 +1,134 @@ + + + + + + + + 2.1 + 2.0 + F001-1 + 2019-12-24 + 01 + PEN + + 12345678912 + + + 12345678912 + + + + + + + + #PROJECT-OPENUBL-SIGN + + + + + + + 12345678912 + + + + + 0000 + + + + + + + + 12121212121 + + + + + + + + FormaPago + Contado + + + 36.00 + + 200.00 + 36.00 + + S + + 1000 + IGV + VAT + + + + + + 200.00 + 236.00 + 0 + 0 + 236.00 + + + 1 + 2 + 200.00 + + + 118.00 + 01 + + + + 36.00 + + 200.00 + 36.00 + + S + 18.00 + 10 + + 1000 + IGV + VAT + + + + + + + + Marca + BRA + Samsung + + + Color + COL + Negro + + + + 100.00 + + + From bf34a4fb22be696c8451dbf32c805a1306f4702c Mon Sep 17 00:00:00 2001 From: Carlos Feria <2582866+carlosthe19916@users.noreply.github.com> Date: Mon, 2 Mar 2026 23:06:20 +0100 Subject: [PATCH 2/3] fix: struct --- xbuilder/src/models/common.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/xbuilder/src/models/common.rs b/xbuilder/src/models/common.rs index f842f054..27514766 100644 --- a/xbuilder/src/models/common.rs +++ b/xbuilder/src/models/common.rs @@ -140,6 +140,17 @@ pub struct DocumentoRelacionado { pub serie_numero: &'static str, } +/// Atributo adicional de un detalle +#[derive(Clone, Debug, Serialize, Default)] +pub struct Atributo { + pub nombre: &'static str, + pub codigo: &'static str, + pub valor: Option<&'static str>, + pub fecha_inicio: Option, + pub fecha_fin: Option, + pub duracion: Option, +} + /// Detalle de las ventas en Boleta/Factura/Nota Credito/Nota Debito #[derive(Clone, Debug, Serialize, Default)] pub struct Detalle { @@ -173,6 +184,8 @@ pub struct Detalle { pub isc_base_imponible: Option, pub total_impuestos: Option, + + pub atributos: Vec, } /// Total Importe Invoice From 95f422115aade199c6d338d6a96c49404d78eeb8 Mon Sep 17 00:00:00 2001 From: Carlos Feria <2582866+carlosthe19916@users.noreply.github.com> Date: Tue, 3 Mar 2026 08:21:44 +0100 Subject: [PATCH 3/3] fix: templating Signed-off-by: Carlos Feria <2582866+carlosthe19916@users.noreply.github.com> --- .../ubl/standard/include/document-line.xml | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/xbuilder/resources/templates/ubl/standard/include/document-line.xml b/xbuilder/resources/templates/ubl/standard/include/document-line.xml index 15819271..7656d435 100644 --- a/xbuilder/resources/templates/ubl/standard/include/document-line.xml +++ b/xbuilder/resources/templates/ubl/standard/include/document-line.xml @@ -73,6 +73,28 @@ {{item.codigo_sunat}} {%- endif %} + {%- for atributo in item.atributos %} + + {{atributo.nombre}} + {{atributo.codigo}} + {%- if atributo.valor %} + {{atributo.valor}} + {%- endif %} + {%- if atributo.fecha_inicio or atributo.fecha_fin or atributo.duracion %} + + {%- if atributo.fecha_inicio %} + {{atributo.fecha_inicio}} + {%- endif %} + {%- if atributo.fecha_fin %} + {{atributo.fecha_fin}} + {%- endif %} + {%- if atributo.duracion %} + {{atributo.duracion}} + {%- endif %} + + {%- endif %} + + {%- endfor %} {{item.precio | round_decimal}}