OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 180 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
 * 
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each file.
 */
 
 package org.openconcerto.erp.core.supplychain.purchase.importer;

import org.openconcerto.sql.model.DBRoot;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.Namespace;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;

/**
 * FacturX export (EN 16931 format)
 */
public class FacturXExporter {

    private class Tax {
        // Taux, ex pour 20% : 20.00
        BigDecimal rate;
        // Montant de la TVA
        BigDecimal amount;

        // montant HT sur lequel s'applique la TVA
        BigDecimal basisAmount;

    }

    public static Namespace QDT_NS = Namespace.getNamespace("qdt", "urn:un:unece:uncefact:data:standard:QualifiedDataType:100");
    public static Namespace RAM_NS = Namespace.getNamespace("ram", "urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100");
    public static Namespace RSM_NS = Namespace.getNamespace("rsm", "urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100");
    public static Namespace UDT_NS = Namespace.getNamespace("udt", "urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100");
    public static Namespace XSI_NS = Namespace.getNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");

    public static void main(String[] args) {

        FacturXExporter ex = new FacturXExporter();
        System.err.println("FacturXExporter.main() " + ex.checkEAN13("5987854125989"));
        String xml = ex.createXMLFrom(null, 1);
        System.out.println(xml);
    }

    public String createXMLFrom(DBRoot row, int invoiceId) {

        List<Tax> taxes = new ArrayList<>();
        Tax t1 = new Tax();
        t1.rate = new BigDecimal("20.0");
        t1.amount = new BigDecimal("40.0");
        t1.basisAmount = new BigDecimal("200.0");
        taxes.add(t1);

        DecimalFormat format = new DecimalFormat("#0.00", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
        DecimalFormat fQty = new DecimalFormat("#0.########", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
        String invoiceNumber = "-";
        Date invoiceDate = new Date();
        String regNote = "SARL au capital de 50 000 EUR";
        String legNote = "RCS MAVILLE 123 456 789";
        int nbLines = 4;

        final Document doc = new Document();
        Element root = new Element("CrossIndustryInvoice", RSM_NS);
        root.addNamespaceDeclaration(QDT_NS);
        root.addNamespaceDeclaration(RAM_NS);
        root.addNamespaceDeclaration(RSM_NS);
        root.addNamespaceDeclaration(UDT_NS);
        root.addNamespaceDeclaration(XSI_NS);

        doc.setRootElement(root);

        // ExchangedDocumentContext : Le truc qui s'ecrirait en une ligne si les génies, grands
        // créateurs de cette norme, connaissaient la notion d'attributs...
        Element eDC = new Element("ExchangedDocumentContext", RSM_NS);
        Element bPSDCP = new Element("BusinessProcessSpecifiedDocumentContextParameter", RAM_NS);
        final Element bPSDCP_ID = new Element("ID", RAM_NS);
        // CHORUSPRO specifications: A1 (invoice deposit), A2 (prepaid invoice deposit)...
        bPSDCP_ID.setText("A1");
        bPSDCP.addContent(bPSDCP_ID);
        eDC.addContent(bPSDCP);
        Element bGSDCP = new Element("GuidelineSpecifiedDocumentContextParameter", RAM_NS);
        final Element bGSDCP_ID = new Element("ID", RAM_NS);
        // For Profile EN 16931 (Comfort):
        bGSDCP_ID.setText("urn:cen.eu:en16931:2017");
        bGSDCP.addContent(bGSDCP_ID);
        eDC.addContent(bGSDCP);
        root.addContent(eDC);

        // ExchangedDocument
        Element ed = new Element("ExchangedDocument", RSM_NS);
        Element edID = new Element("ID", RAM_NS);
        if (invoiceNumber.length() > 20) {
            // CHORUSPRO: the invoice number is limited to 20 characters (lol)
            invoiceNumber = invoiceNumber.substring(0, 20);
        }
        edID.setText(invoiceNumber);
        ed.addContent(edID);
        Element edTypeCode = new Element("TypeCode", RAM_NS);
        // The types of documents used are:
        // 380: Commercial Invoice
        // 381: Credit note
        // 384: Corrected invoice
        // 389: Self-billied invoice (created by the buyer on behalf of the supplier)
        // 261: Self billed credit note (not accepted by CHORUSPRO)
        // 386: Prepayment invoice
        // 751: Invoice information for accounting purposes (not accepted by CHORUSPRO)
        edTypeCode.setText("380");
        ed.addContent(edTypeCode);
        Element edIssueDateTime = new Element("IssueDateTime", RAM_NS);
        addDateTime(invoiceDate, edIssueDateTime);
        ed.addContent(edIssueDateTime);
        addIncludedNote(regNote, "REG", ed);
        addIncludedNote(legNote, "ABL", ed);

        // SupplyChainTradeTransaction
        Element eSupplyChainTradeTransaction = new Element("SupplyChainTradeTransaction", RSM_NS);
        for (int i = 0; i < nbLines; i++) {
            String productCode = "a";
            String productName = "b";

            BigDecimal pHT = new BigDecimal("12.46");
            BigDecimal tax = new BigDecimal("0.20");
            BigDecimal pTTC = new BigDecimal("14.95");
            BigDecimal qte = new BigDecimal("10.0");
            BigDecimal totalHTLigne = new BigDecimal("124.60");

            Element eLineItem = new Element("IncludedSupplyChainTradeLineItem", RAM_NS);
            // AssociatedDocumentLineDocument
            Element eAssociatedDocumentLineDocument = new Element("AssociatedDocumentLineDocument", RAM_NS);
            Element eLineID = new Element("LineID", RAM_NS);
            eLineID.setText(String.valueOf(i + 1));
            eAssociatedDocumentLineDocument.addContent(eLineID);
            eLineItem.addContent(eAssociatedDocumentLineDocument);
            // SpecifiedTradeProduct
            Element eSpecifiedTradeProduct = new Element("SpecifiedTradeProduct", RAM_NS);
            if (!productCode.isEmpty()) {
                Element eGlobalID = new Element("GlobalID", RAM_NS);
                if (productCode.length() > 40) {
                    // CHORUSPRO: this field is limited to 40 characters
                    productCode = productCode.substring(0, 40);
                }
                if (checkEAN13(productCode)) {
                    // 0088 : EAN
                    eGlobalID.setAttribute("schemeID", "0088");
                } else {
                    // 0197 : Not Known
                    eGlobalID.setAttribute("schemeID", "0197");
                }
                eGlobalID.setText(productCode);
                eSpecifiedTradeProduct.addContent(eGlobalID);
            }
            Element eName = new Element("Name", RAM_NS);
            eName.setText(productName);
            eSpecifiedTradeProduct.addContent(eName);
            eLineItem.addContent(eSpecifiedTradeProduct);
            //
            Element eSpecifiedLineTradeAgreement = new Element("SpecifiedLineTradeAgreement", RAM_NS);
            // Prix unitaire TTC
            Element eGrossPriceProductTradePrice = new Element("GrossPriceProductTradePrice", RAM_NS);
            Element eChargeAmount = new Element("ChargeAmount", RAM_NS);
            eChargeAmount.setText(format.format(pTTC));
            eGrossPriceProductTradePrice.addContent(eChargeAmount);
            Element eAppliedTradeAllowanceCharge = new Element("AppliedTradeAllowanceCharge", RAM_NS);
            Element eChargeIndicator = new Element("ChargeIndicator", RAM_NS);
            Element eIndicator = new Element("ChargeIndicator", UDT_NS);
            // pas de remise
            eIndicator.setText("false");
            eChargeIndicator.addContent(eIndicator);
            eAppliedTradeAllowanceCharge.addContent(eChargeIndicator);

            Element eActualAmount = new Element("ActualAmount", RAM_NS);
            // Montant de TVA (unitaire)
            eActualAmount.setText(format.format(pTTC.subtract(pHT)));

            eAppliedTradeAllowanceCharge.addContent(eActualAmount);

            eGrossPriceProductTradePrice.addContent(eAppliedTradeAllowanceCharge);

            eSpecifiedLineTradeAgreement.addContent(eGrossPriceProductTradePrice);
            // Prix unitaire HT
            Element eNetPriceProductTradePrice = new Element("NetPriceProductTradePrice", RAM_NS);
            Element eChargeAmountHT = new Element("ChargeAmount", RAM_NS);
            eChargeAmountHT.setText(format.format(pHT));

            eNetPriceProductTradePrice.addContent(eChargeAmountHT);
            eSpecifiedLineTradeAgreement.addContent(eNetPriceProductTradePrice);
            eLineItem.addContent(eSpecifiedLineTradeAgreement);

            // Quantité

            Element eSpecifiedLineTradeDelivery = new Element("SpecifiedLineTradeDelivery", RAM_NS);

            // LTR = Liter (1 dm3), MTQ = cubic meter , KGM = Kilogram , MTR = Meter , C62 = Unit ,
            // TNE = Tonne
            // TODO : gerer les unités
            Element eBilledQuantity = new Element("BilledQuantity", RAM_NS);
            eBilledQuantity.setAttribute("unitCode", "C62");
            eBilledQuantity.setText(fQty.format(qte));

            eSpecifiedLineTradeDelivery.addContent(eBilledQuantity);
            eLineItem.addContent(eSpecifiedLineTradeDelivery);

            Element eSpecifiedLineTradeSettlement = new Element("SpecifiedLineTradeSettlement", RAM_NS);
            Element eApplicableTradeTaxt = new Element("ApplicableTradeTax", RAM_NS);

            Element eTypeCode = new Element("TypeCode", RAM_NS);
            eTypeCode.setText("VAT");
            eApplicableTradeTaxt.addContent(eTypeCode);

            // S = Taux de TVA standard
            // E = Exempté de TVA
            // AE = Autoliquidation de TVA
            // K = Autoliquidation pour cause de livraison intracommunautaire
            // G = Exempté de TVA pour Export hors UE
            // O = Hors du périmètre d'application de la TVA
            // L = Iles Canaries
            // M = Ceuta et Mellila
            // TODO : TVA 0
            Element eCategoryCode = new Element("CategoryCode", RAM_NS);
            eCategoryCode.setText("S");
            eApplicableTradeTaxt.addContent(eCategoryCode);

            Element eRateApplicablePercent = new Element("RateApplicablePercent", RAM_NS);
            // 20% -> 20.0
            eRateApplicablePercent.setText(format.format(tax.multiply(new BigDecimal(100))));
            eApplicableTradeTaxt.addContent(eRateApplicablePercent);

            eSpecifiedLineTradeSettlement.addContent(eApplicableTradeTaxt);

            Element eSpecifiedTradeSettlementLineMonetarySummation = new Element("SpecifiedTradeSettlementLineMonetarySummation", RAM_NS);
            // Total HT
            Element eLineTotalAmount = new Element("LineTotalAmount", RAM_NS);
            eLineTotalAmount.setText(format.format(totalHTLigne));
            eSpecifiedTradeSettlementLineMonetarySummation.addContent(eLineTotalAmount);
            eSpecifiedLineTradeSettlement.addContent(eSpecifiedTradeSettlementLineMonetarySummation);

            eLineItem.addContent(eSpecifiedLineTradeSettlement);
            //
            eSupplyChainTradeTransaction.addContent(eLineItem);
        }

        addApplicableHeader(eSupplyChainTradeTransaction, taxes);

        ed.addContent(eSupplyChainTradeTransaction);

        root.addContent(ed);

        final XMLOutputter xmlOutput = new XMLOutputter();
        xmlOutput.setFormat(Format.getPrettyFormat());
        return xmlOutput.outputString(doc);
    }

    public void addValue(Element parent, Element element, String value) {
        element.setText(value);
        parent.addContent(element);
    }

    private void addApplicableHeader(Element eSupplyChainTradeTransaction, List<Tax> taxes) {
        //
        // ApplicableHeaderTradeAgreement
        //
        final Element eApplicableHeaderTradeAgreement = new Element("ApplicableHeaderTradeAgreement", RAM_NS);
        addSupplierInfo(eApplicableHeaderTradeAgreement);
        addBuyerInfo(eApplicableHeaderTradeAgreement);

        String orderRef = "";
        String contractRef = "";
        // Date de livraison, facultative
        Date effectiveDeliveryDate = new Date(65454654);
        String invoiceNumber = "FA-2017-0010";
        String currencyCode = "EUR";
        String dueDescription = "30% d'acompte, solde à 30 j";
        Date dueDate = new Date(65455654);

        final Element eBuyerOrderReferencedDocument = new Element("BuyerOrderReferencedDocument", RAM_NS);
        addValue(eBuyerOrderReferencedDocument, new Element("IssuerAssignedID", RAM_NS), orderRef);
        eApplicableHeaderTradeAgreement.addContent(eBuyerOrderReferencedDocument);

        final Element eContractReferencedDocument = new Element("ContractReferencedDocument", RAM_NS);
        addValue(eContractReferencedDocument, new Element("IssuerAssignedID", RAM_NS), contractRef);

        eApplicableHeaderTradeAgreement.addContent(eContractReferencedDocument);
        eSupplyChainTradeTransaction.addContent(eApplicableHeaderTradeAgreement);

        //
        // ApplicableHeaderTradeDelivery
        //
        final Element eApplicableHeaderTradeDelivery = new Element("ApplicableHeaderTradeDelivery", RAM_NS);

        // <ram:ShipToTradeParty>
        // <ram:PostalTradeAddress>
        // <ram:PostcodeCode>69001</ram:PostcodeCode>
        // <ram:LineOne>35 rue de la République</ram:LineOne>
        // <ram:CityName>Lyon</ram:CityName>
        // <ram:CountryID>FR</ram:CountryID>
        // </ram:PostalTradeAddress>
        // </ram:ShipToTradeParty>
        if (effectiveDeliveryDate != null) {
            // Date de livraison effective (facultative)
            final Element eActualDeliverySupplyChainEvent = new Element("ActualDeliverySupplyChainEvent", RAM_NS);
            final Element eOccurrenceDateTime = new Element("OccurrenceDateTime", RAM_NS);
            addDateTime(effectiveDeliveryDate, eOccurrenceDateTime);
            eActualDeliverySupplyChainEvent.addContent(eOccurrenceDateTime);
            eApplicableHeaderTradeDelivery.addContent(eActualDeliverySupplyChainEvent);
        }
        eSupplyChainTradeTransaction.addContent(eApplicableHeaderTradeDelivery);

        //
        // ApplicableHeaderTradeSettlement
        //
        final Element eApplicableHeaderTradeSettlement = new Element("ApplicableHeaderTradeSettlement", RAM_NS);
        addValue(eApplicableHeaderTradeSettlement, new Element("PaymentReference", RAM_NS), invoiceNumber);
        addValue(eApplicableHeaderTradeSettlement, new Element("InvoiceCurrencyCode", RAM_NS), currencyCode);
        final Element aSpecifiedTradeSettlementPaymentMeans = new Element("SpecifiedTradeSettlementPaymentMeans", RAM_NS);

        // <ram:TypeCode>30</ram:TypeCode>
        // <ram:Information>Virement sur compte Banque Fiducial</ram:Information>
        // <ram:PayeePartyCreditorFinancialAccount>
        // <ram:IBANID>FR2012421242124212421242124</ram:IBANID>
        // </ram:PayeePartyCreditorFinancialAccount>
        // <ram:PayeeSpecifiedCreditorFinancialInstitution>
        // <ram:BICID>FIDCFR21XXX</ram:BICID>
        // </ram:PayeeSpecifiedCreditorFinancialInstitution>

        eApplicableHeaderTradeSettlement.addContent(aSpecifiedTradeSettlementPaymentMeans);
        DecimalFormat format = new DecimalFormat("#0.00", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
        for (Tax t : taxes) {
            final Element aApplicableTradeTax = new Element("ApplicableTradeTax", RAM_NS);
            // Montant de la TVA
            addValue(aApplicableTradeTax, new Element("CalculatedAmount", RAM_NS), format.format(t.amount));
            // LOL
            addValue(aApplicableTradeTax, new Element("TypeCode", RAM_NS), "VAT");
            // montant HT sur lequel s'applique la TVA
            addValue(aApplicableTradeTax, new Element("BasisAmount", RAM_NS), format.format(t.basisAmount));
            // S = Taux de TVA standard
            // E = Exempté de TVA
            // AE = Autoliquidation de TVA
            // K = Autoliquidation pour cause de livraison intracommunautaire
            // G = Exempté de TVA pour Export hors UE
            // O = Hors du périmètre d'application de la TVA
            // L = Iles Canaries
            // M = Ceuta et Mellila
            // TODO : TVA 0
            addValue(aApplicableTradeTax, new Element("CategoryCode", RAM_NS), "S");

            // TODO : type de TVA :
            // 5 : Date de la facture (TVA sur DEBITS)
            // 29 : Date de livraison (TVA sur DEBITS)
            // 72 : Date de paiement (TVA sur ENCAISSEMENTS)
            addValue(aApplicableTradeTax, new Element("DueDateTypeCode", RAM_NS), "5");

            addValue(aApplicableTradeTax, new Element("RateApplicablePercent", RAM_NS), format.format(t.rate));
            eApplicableHeaderTradeSettlement.addContent(aApplicableTradeTax);
        }

        final Element eSpecifiedTradePaymentTerms = new Element("SpecifiedTradePaymentTerms", RAM_NS);
        addValue(eSpecifiedTradePaymentTerms, new Element("Description", RAM_NS), dueDescription);

        final Element eDueDateDateTime = new Element("DueDateDateTime", RAM_NS);
        addDateTime(dueDate, eDueDateDateTime);
        eSpecifiedTradePaymentTerms.addContent(eDueDateDateTime);
        eApplicableHeaderTradeSettlement.addContent(eSpecifiedTradePaymentTerms);

        final Element eSpecifiedTradeSettlementHeaderMonetarySummation = new Element("SpecifiedTradeSettlementHeaderMonetarySummation", RAM_NS);

        // Total HT
        // <ram:LineTotalAmount>624.90</ram:LineTotalAmount>
        // Total HT sur leque est appliqué la TVA
        // <ram:TaxBasisTotalAmount>624.90</ram:TaxBasisTotalAmount>
        // Total des TVA
        // <ram:TaxTotalAmount currencyID="EUR">46.25</ram:TaxTotalAmount>
        // Total TTC
        // <ram:GrandTotalAmount>671.15</ram:GrandTotalAmount>
        // Montant déjà payé
        // <ram:TotalPrepaidAmount>201.00</ram:TotalPrepaidAmount>
        // Reste à payer
        // <ram:DuePayableAmount>470.15</ram:DuePayableAmount>

        eApplicableHeaderTradeSettlement.addContent(eSpecifiedTradeSettlementHeaderMonetarySummation);

        eSupplyChainTradeTransaction.addContent(eApplicableHeaderTradeSettlement);

    }

    private void addBuyerInfo(final Element eApplicableHeaderTradeAgreement) {
        // Acheteur
        String buyerName = "Ma jolie boutique";
        String buyerSIRET = "78787878400035";
        String buyerVAT = "FR19787878784";
        String buyerContactName = "Alexandre Payet";
        String buyerPhone = "+33 4 72 07 08 67";
        String buyerEmail = "alexandre.payet@majolieboutique.net";
        String buyerAddrL1 = "35 rue de la République";
        String buyerAddrL2 = "";
        String buyerAddrL3 = "";
        String buyerPostalCode = "69001";
        String buyerCity = "Lyon";
        String buyerCountryCode = "FR";

        final Element eBuyerTradeParty = new Element("BuyerTradeParty", RAM_NS);
        this.addValue(eBuyerTradeParty, new Element("Name", RAM_NS), buyerName);

        final Element eSpecifiedLegalOrganization = new Element("SpecifiedLegalOrganization", RAM_NS);
        Element eSpecifiedLegalOrganizationId = new Element("ID", RAM_NS);
        eSpecifiedLegalOrganizationId.setAttribute("schemeID", "0002");
        eSpecifiedLegalOrganizationId.setText(buyerSIRET);
        eSpecifiedLegalOrganization.addContent(eSpecifiedLegalOrganizationId);
        eBuyerTradeParty.addContent(eSpecifiedLegalOrganization);
        // Contact
        final Element eDefinedTradeContact = new Element("DefinedTradeContact", RAM_NS);
        addValue(eDefinedTradeContact, new Element("PersonName", RAM_NS), buyerContactName);
        final Element eTelephoneUniversalCommunication = new Element("TelephoneUniversalCommunication", RAM_NS);
        addValue(eTelephoneUniversalCommunication, new Element("CompleteNumber", RAM_NS), buyerPhone);
        eDefinedTradeContact.addContent(eTelephoneUniversalCommunication);
        final Element eEmailURIUniversalCommunication = new Element("EmailURIUniversalCommunication", RAM_NS);
        final Element eURIID = new Element("URIID", RAM_NS);
        eURIID.setAttribute("schemeID", "SMTP");
        eURIID.setText(buyerEmail);
        eEmailURIUniversalCommunication.addContent(eURIID);
        eDefinedTradeContact.addContent(eEmailURIUniversalCommunication);
        eBuyerTradeParty.addContent(eDefinedTradeContact);
        // Adresse postale
        final Element ePostalTradeAddress = new Element("PostalTradeAddress", RAM_NS);
        addValue(ePostalTradeAddress, new Element("LineOne>", RAM_NS), buyerAddrL1);
        if (buyerAddrL2 != null && !buyerAddrL2.trim().isEmpty()) {
            addValue(ePostalTradeAddress, new Element("LineTwo>", RAM_NS), buyerAddrL2);
        }
        if (buyerAddrL3 != null && !buyerAddrL3.trim().isEmpty()) {
            addValue(ePostalTradeAddress, new Element("LineThree>", RAM_NS), buyerAddrL3);
        }
        addValue(ePostalTradeAddress, new Element("PostcodeCode>", RAM_NS), buyerPostalCode);
        addValue(ePostalTradeAddress, new Element("CityName>", RAM_NS), buyerCity);
        addValue(ePostalTradeAddress, new Element("CountryID>", RAM_NS), buyerCountryCode);

        eBuyerTradeParty.addContent(ePostalTradeAddress);

        // TVA
        final Element eSpecifiedTaxRegistration = new Element("SpecifiedTaxRegistration", RAM_NS);
        final Element eSpecifiedTaxRegistrationId = new Element("ID", RAM_NS);
        eSpecifiedTaxRegistrationId.setAttribute("schemeID", "VA");
        eSpecifiedTaxRegistrationId.setText(buyerVAT);
        eSpecifiedTaxRegistration.addContent(eSpecifiedTaxRegistrationId);
        eBuyerTradeParty.addContent(eSpecifiedTaxRegistration);

        eApplicableHeaderTradeAgreement.addContent(eBuyerTradeParty);
    }

    private void addSupplierInfo(final Element eApplicableHeaderTradeAgreement) {
        String supplierName = "Au bon moulin";
        String supplierSIRET = "121321321321";
        String supplierContactName = "Tony Dubois";
        String supplierContactPhone = "+33 4 72 07 08 56";
        String supplierContactEmail = "tony.dubois@aubonmoulin.fr";
        String supplierAddrL1 = "3 rue du pont";
        String supplierAddrL2 = "";
        String supplierAddrL3 = "";
        String supplierAddrPostalCode = "80100";
        String supplierAddrCityName = "Abbeville";
        String supplierAddrCountryID = "FR";
        String supplierNumTVA = "FR121321321321";
        // Vendeur
        final Element eSellerTradeParty = new Element("SellerTradeParty", RAM_NS);
        addValue(eSellerTradeParty, new Element("Name", RAM_NS), supplierName);

        final Element eSpecifiedLegalOrganization = new Element("SpecifiedLegalOrganization", RAM_NS);
        final Element eID = new Element("ID", RAM_NS);
        eID.setAttribute("schemeID", "0002");
        eID.setText(supplierSIRET);
        eSpecifiedLegalOrganization.addContent(eID);
        eSellerTradeParty.addContent(eSpecifiedLegalOrganization);

        final Element eDefinedTradeContact = new Element("DefinedTradeContact", RAM_NS);
        final Element ePersonName = new Element("PersonName", RAM_NS);
        ePersonName.setText(supplierContactName);
        eDefinedTradeContact.addContent(ePersonName);

        final Element eTelephoneUniversalCommunication = new Element("TelephoneUniversalCommunication", RAM_NS);
        final Element eCompleteNumber = new Element("CompleteNumber", RAM_NS);
        eCompleteNumber.setText(supplierContactPhone);
        eTelephoneUniversalCommunication.addContent(eCompleteNumber);
        eDefinedTradeContact.addContent(eTelephoneUniversalCommunication);

        final Element eEmailURIUniversalCommunication = new Element("EmailURIUniversalCommunication", RAM_NS);
        final Element eURIID = new Element("URIID", RAM_NS);
        eURIID.setAttribute("schemeID", "SMTP");
        eURIID.setText(supplierContactEmail);
        eEmailURIUniversalCommunication.addContent(eURIID);
        eDefinedTradeContact.addContent(eEmailURIUniversalCommunication);
        eSellerTradeParty.addContent(eDefinedTradeContact);

        final Element ePostalTradeAddress = new Element("PostalTradeAddress", RAM_NS);
        addValue(ePostalTradeAddress, new Element("LineOne", RAM_NS), supplierAddrL1);
        if (supplierAddrL2 != null && !supplierAddrL2.trim().isEmpty()) {
            addValue(ePostalTradeAddress, new Element("LineTwo", RAM_NS), supplierAddrL2);
        }
        if (supplierAddrL3 != null && !supplierAddrL3.trim().isEmpty()) {
            addValue(ePostalTradeAddress, new Element("LineThree", RAM_NS), supplierAddrL3);
        }
        addValue(ePostalTradeAddress, new Element("PostcodeCode", RAM_NS), supplierAddrPostalCode);
        addValue(ePostalTradeAddress, new Element("CityName", RAM_NS), supplierAddrCityName);
        addValue(ePostalTradeAddress, new Element("CountryID", RAM_NS), supplierAddrCountryID);

        eSellerTradeParty.addContent(ePostalTradeAddress);

        final Element eSpecifiedTaxRegistration = new Element("SpecifiedTaxRegistration", RAM_NS);
        final Element eSpecifiedTaxRegistrationID = new Element("ID", RAM_NS);
        eSpecifiedTaxRegistrationID.setAttribute("schemeID", "VA");
        eSpecifiedTaxRegistrationID.setText(supplierNumTVA);
        eSpecifiedTaxRegistration.addContent(eSpecifiedTaxRegistrationID);
        eSellerTradeParty.addContent(eSpecifiedTaxRegistration);

        eApplicableHeaderTradeAgreement.addContent(eSellerTradeParty);
    }

    private void addIncludedNote(String content, String code, Element ed) {
        final Element e = new Element("IncludedNote", RAM_NS);
        final Element eContent = new Element("Content", RAM_NS);
        eContent.setText(content);
        e.addContent(eContent);
        final Element eCode = new Element("SubjectCode", RAM_NS);
        eCode.setText(code);
        e.addContent(eCode);
        ed.addContent(e);
    }

    private void addDateTime(Date date, Element eTime) {
        final Element e = new Element("DateTimeString", UDT_NS);
        // From the doc : Only value "102" ...
        e.setAttribute("format", "102");
        SimpleDateFormat s = new SimpleDateFormat("yyyyMMdd");
        e.setText(s.format(date));
        eTime.addContent(e);
    }

    boolean checkEAN13(String code) {
        if (code == null || code.length() != 13) {
            return false;
        }
        int checkdigit = 0;
        for (int i = 1; i < 12; i += 2) {
            checkdigit += Integer.valueOf(code.substring(i, i + 1));
        }
        checkdigit *= 3;
        for (int i = 0; i < 11; i += 2) {
            checkdigit += Integer.valueOf(code.substring(i, i + 1));
        }
        checkdigit %= 10;
        if (checkdigit != 0) {
            checkdigit = 10 - checkdigit;
        }
        return Integer.valueOf(code.substring(12, 13)).intValue() == checkdigit;
    }
}