import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.apache.camel.component.smooks.utils.SmooksCaches;
import org.smooks.edifact.binding.d96a.ALCAllowanceOrCharge;
import org.smooks.edifact.binding.d96a.BGMBeginningOfMessage;
import org.smooks.edifact.binding.d96a.C002DocumentMessageName;
import org.smooks.edifact.binding.d96a.C056DepartmentOrEmployeeDetails;
import org.smooks.edifact.binding.d96a.C059Street;
import org.smooks.edifact.binding.d96a.C078AccountIdentification;
import org.smooks.edifact.binding.d96a.C080PartyName;
import org.smooks.edifact.binding.d96a.C082PartyIdentificationDetails;
import org.smooks.edifact.binding.d96a.C088InstitutionIdentification;
import org.smooks.edifact.binding.d96a.C108TextLiteral;
import org.smooks.edifact.binding.d96a.C110PaymentTerms;
import org.smooks.edifact.binding.d96a.C112TermsTimeInformation;
import org.smooks.edifact.binding.d96a.C128RateDetails;
import org.smooks.edifact.binding.d96a.C186QuantityDetails;
import org.smooks.edifact.binding.d96a.C212ItemNumberIdentification;
import org.smooks.edifact.binding.d96a.C241DutyTaxFeeType;
import org.smooks.edifact.binding.d96a.C243DutyTaxFeeDetail;
import org.smooks.edifact.binding.d96a.C273ItemDescription;
import org.smooks.edifact.binding.d96a.C501PercentageDetails;
import org.smooks.edifact.binding.d96a.C504CurrencyDetails;
import org.smooks.edifact.binding.d96a.C506Reference;
import org.smooks.edifact.binding.d96a.C507DateTimePeriod;
import org.smooks.edifact.binding.d96a.C509PriceInformation;
import org.smooks.edifact.binding.d96a.C516MonetaryAmount;
import org.smooks.edifact.binding.d96a.C533DutyTaxFeeAccountDetail;
import org.smooks.edifact.binding.d96a.C534PaymentInstructionDetails;
import org.smooks.edifact.binding.d96a.C552AllowanceChargeInformation;
import org.smooks.edifact.binding.d96a.CTAContactInformation;
import org.smooks.edifact.binding.d96a.CUXCurrencies;
import org.smooks.edifact.binding.d96a.DTMDateTimePeriod;
import org.smooks.edifact.binding.d96a.E1153ReferenceQualifier;
import org.smooks.edifact.binding.d96a.E3035PartyQualifier;
import org.smooks.edifact.binding.d96a.E3139ContactFunctionCoded;
import org.smooks.edifact.binding.d96a.E4451TextSubjectQualifier;
import org.smooks.edifact.binding.d96a.E5125PriceQualifier;
import org.smooks.edifact.binding.d96a.E5153DutyTaxFeeTypeCoded;
import org.smooks.edifact.binding.d96a.E5387PriceTypeQualifier;
import org.smooks.edifact.binding.d96a.E5463AllowanceOrChargeQualifier;
import org.smooks.edifact.binding.d96a.E7143ItemNumberTypeCoded;
import org.smooks.edifact.binding.d96a.FIIFinancialInstitutionInformation;
import org.smooks.edifact.binding.d96a.FTXFreeText;
import org.smooks.edifact.binding.d96a.IMDItemDescription;
import org.smooks.edifact.binding.d96a.INVOIC;
import org.smooks.edifact.binding.d96a.Interchange;
import org.smooks.edifact.binding.d96a.LINLineItem;
import org.smooks.edifact.binding.d96a.MOAMonetaryAmount;
import org.smooks.edifact.binding.d96a.Message;
import org.smooks.edifact.binding.d96a.NADNameAndAddress;
import org.smooks.edifact.binding.d96a.PAIPaymentInstructions;
import org.smooks.edifact.binding.d96a.PATPaymentTermsBasis;
import org.smooks.edifact.binding.d96a.PCDPercentageDetails;
import org.smooks.edifact.binding.d96a.PIAAdditionalProductId;
import org.smooks.edifact.binding.d96a.PRIPriceDetails;
import org.smooks.edifact.binding.d96a.QTYQuantity;
import org.smooks.edifact.binding.d96a.RFFReference;
import org.smooks.edifact.binding.d96a.RTERateDetails;
import org.smooks.edifact.binding.d96a.TAXDutyTaxFeeDetails;
import org.smooks.edifact.binding.service.E0001SyntaxIdentifier;
import org.smooks.edifact.binding.service.E0051ControllingAgencyCoded;
import org.smooks.edifact.binding.service.E0065MessageType;
import org.smooks.edifact.binding.service.E0081SectionIdentification;
import org.smooks.edifact.binding.service.S001SyntaxIdentifier;
import org.smooks.edifact.binding.service.S002InterchangeSender;
import org.smooks.edifact.binding.service.S003InterchangeRecipient;
import org.smooks.edifact.binding.service.S004DateAndTimeOfPreparation;
import org.smooks.edifact.binding.service.S005RecipientReferencePasswordDetails;
import org.smooks.edifact.binding.service.S009MessageIdentifier;
import org.smooks.edifact.binding.service.UNA;
import org.smooks.edifact.binding.service.UNBInterchangeHeader;
import org.smooks.edifact.binding.service.UNHMessageHeader;
import org.smooks.edifact.binding.service.UNSSectionControl;
import org.smooks.edifact.binding.service.UNTMessageTrailer;
import org.smooks.edifact.binding.service.UNZInterchangeTrailer;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public static boolean isEmpty(String val) {
    return val == null || val.equals("");
}

String invoicJsonStr = exchange.getMessage().getBody(String.class);
JSONObject invoicJson = JSON.parseObject(invoicJsonStr);

Interchange interchange = new Interchange();

// UNA
interchange.withUNA(
        new UNA()
                .withCompositeSeparator(":")
                .withFieldSeparator("+")
                .withDecimalSeparator(".")
                .withEscapeCharacter("?")
                .withRepeatSeparator("*")
                .withSegmentTerminator("'")
);

// UNB
String supplierId = invoicJson.getString("supplierId");
String siretNumber = invoicJson.getString("siretNumber");
if (!isEmpty(supplierId) && !isEmpty(siretNumber)) {
    // 获取当前日期和时间
    LocalDate date = LocalDate.now();
    LocalTime time = LocalTime.now();

    // 格式化
    String formattedDate = date.format(DateTimeFormatter.ofPattern("yyMMdd"));
    String formattedTime = time.format(DateTimeFormatter.ofPattern("HHmm"));

    interchange.withUNB(
            new UNBInterchangeHeader()
                    .withS001(
                            new S001SyntaxIdentifier()
                                    .withE0001(E0001SyntaxIdentifier.UNOC)
                                    .withE0002("3")
                    )
                    .withS002(
                            new S002InterchangeSender()
                                    // supplierId
                                    .withE0004(supplierId)
                                    .withE0007("14")
                    )
                    .withS003(
                            new S003InterchangeRecipient()
                                    // siretNumber
                                    .withE0010(siretNumber)
                                    .withE0007("14")
                    )
                    .withS004(
                            new S004DateAndTimeOfPreparation()
                                    // date
                                    .withE0017(BigDecimal.valueOf(Long.valueOf(formattedDate)))
                                    // time
                                    .withE0019(BigDecimal.valueOf(Long.valueOf(formattedTime)))
                    )
                    .withE0020("17")
                    .withS005(
                            new S005RecipientReferencePasswordDetails()
                                    .withE0022("")
                    )
                    .withE0026("INVOIC")
            // test e0035 = 1
            //.withE0035(new BigDecimal(1))
    );
}

Message message = new Message();

// UNH
String headMessageReferenceNum = invoicJson.getString("headMessageReferenceNum");
String associationCode = invoicJson.getString("associationCode");
if (!isEmpty(headMessageReferenceNum) && !isEmpty(associationCode)) {
    message.withContent(
            new JAXBElement<>(
                    new QName("UNH"), UNHMessageHeader.class,
                    new UNHMessageHeader()
                            // headMessageReferenceNum
                            .withE0062(headMessageReferenceNum)
                            .withS009(
                                    new S009MessageIdentifier()
                                            .withE0065(E0065MessageType.INVOIC)
                                            .withE0052("D")
                                            .withE0054("96A")
                                            .withE0051(E0051ControllingAgencyCoded.UN)
                                            // associationCode
                                            .withE0057(associationCode)
                            )
            )
    );
}

INVOIC invoic = new INVOIC();

// BGM
String documentType = invoicJson.getString("documentType");
String documentIdentifier = invoicJson.getString("documentIdentifier");
String messageFunctionCode = invoicJson.getString("messageFunctionCode");
if (!isEmpty(documentType) && !isEmpty(documentIdentifier) && !isEmpty(messageFunctionCode)) {
    invoic.withBGM(
            new BGMBeginningOfMessage()
                    .withC002(
                            new C002DocumentMessageName()
                                    // documentType
                                    .withE1001(documentType)
                    )
                    // documentIdentifier
                    .withE1004(documentIdentifier)
                    // messageFunctionCode
                    .withE1225(messageFunctionCode)
    );
}

// DTM
String invoiceDate = invoicJson.getString("invoiceDate");
if (!isEmpty(invoiceDate)) {
    invoic.withDTM(
            new DTMDateTimePeriod()
                    .withC507(
                            new C507DateTimePeriod()
                                    .withE2005("3")
                                    // invoiceDate
                                    .withE2380(invoiceDate)
                                    .withE2379("102")
                    )
    );
}

// PAI
String paymentInstructions = invoicJson.getString("paymentInstructions");
if (!isEmpty(paymentInstructions)) {
    invoic.withPAI(
            new PAIPaymentInstructions()
                    .withC534(
                            new C534PaymentInstructionDetails()
                                    // paymentInstructions
                                    .withE4461(paymentInstructions)
                    )
    );
}

// FTX
JSONArray vendorInfos = invoicJson.getJSONArray("vendorInfos");
if (vendorInfos != null && vendorInfos.size() > 0) {
    invoic.withFTX(
            new FTXFreeText()
                    .withE4451(E4451TextSubjectQualifier.AAI)
                    .withC108(
                            new C108TextLiteral()
                                    .withE4440(
                                            // vendorInfos
                                            vendorInfos.toArray(new String[0])
                                    )
                    )
    );
}

JSONArray capitalShares = invoicJson.getJSONArray("capitalShares");
if (capitalShares != null && capitalShares.size() > 0) {
    invoic.withFTX(
            new FTXFreeText()
                    .withE4451(E4451TextSubjectQualifier.ABY)
                    .withC108(
                            new C108TextLiteral()
                                    .withE4440(
                                            // capitalShares
                                            capitalShares.toArray(new String[0])
                                    )
                    )
    );
}

JSONArray recoveryCosts = invoicJson.getJSONArray("recoveryCosts");
if (recoveryCosts != null && recoveryCosts.size() > 0) {
    invoic.withFTX(
            new FTXFreeText()
                    .withE4451(E4451TextSubjectQualifier.PMT)
                    .withC108(
                            new C108TextLiteral()
                                    .withE4440(
                                            // recoveryCosts
                                            recoveryCosts.toArray(new String[0])
                                    )
                    )
    );
}

JSONArray discountConditions = invoicJson.getJSONArray("discountConditions");
if (discountConditions != null && discountConditions.size() > 0) {
    invoic.withFTX(
            new FTXFreeText()
                    .withE4451(E4451TextSubjectQualifier.PMD)
                    .withC108(
                            new C108TextLiteral()
                                    .withE4440(
                                            // discountConditions
                                            discountConditions.toArray(new String[0])
                                    )
                    )
    );
}

JSONArray penaltyConditions = invoicJson.getJSONArray("penaltyConditions");
if (penaltyConditions != null && penaltyConditions.size() > 0) {
    invoic.withFTX(
            new FTXFreeText()
                    .withE4451(E4451TextSubjectQualifier.AAB)
                    .withC108(
                            new C108TextLiteral()
                                    .withE4440(
                                            // penaltyConditions
                                            penaltyConditions.toArray(new String[0])
                                    )
                    )
    );
}

JSONArray freeTexts = invoicJson.getJSONArray("freeTexts");
if (freeTexts != null && freeTexts.size() > 0) {
    invoic.withFTX(
            new FTXFreeText()
                    .withE4451(E4451TextSubjectQualifier.ACB)
                    .withC108(
                            new C108TextLiteral()
                                    .withE4440(
                                            // freeTexts
                                            freeTexts.toArray(new String[0])
                                    )
                    )
    );
}

INVOIC.SegGrp1 contractNumberSegGrp1 = null;

// SG1.RFF
String contractNumber = invoicJson.getString("contractNumber");
if (!isEmpty(contractNumber)) {
    if (contractNumberSegGrp1 == null) {
        contractNumberSegGrp1 = new INVOIC.SegGrp1();
    }

    contractNumberSegGrp1.withRFF(
            new RFFReference()
                    .withC506(
                            new C506Reference()
                                    .withE1153(E1153ReferenceQualifier.CT)
                                    .withE1154(contractNumber)
                    )
    );
}

if (contractNumberSegGrp1 != null) {
    invoic.withSegGrp1(contractNumberSegGrp1);
}


INVOIC.SegGrp1 customerOrderNumberSegGrp1 = null;

// SG1.RFF
String customerOrderNumber = invoicJson.getString("customerOrderNumber");
if (!isEmpty(customerOrderNumber)) {
    if (customerOrderNumberSegGrp1 == null) {
        customerOrderNumberSegGrp1 = new INVOIC.SegGrp1();
    }

    customerOrderNumberSegGrp1.withRFF(
            new RFFReference()
                    .withC506(
                            new C506Reference()
                                    .withE1153(E1153ReferenceQualifier.ON)
                                    .withE1154(customerOrderNumber)
                    )
    );
}

if (customerOrderNumberSegGrp1 != null) {
    invoic.withSegGrp1(customerOrderNumberSegGrp1);
}

INVOIC.SegGrp1 referenceSegGrp1 = null;

// SG1.RFF
String referenceDocumentNum = invoicJson.getString("referenceDocumentNum");
if (!isEmpty(referenceDocumentNum)) {
    if (referenceSegGrp1 == null) {
        referenceSegGrp1 = new INVOIC.SegGrp1();
    }

    referenceSegGrp1.withRFF(
            new RFFReference()
                    .withC506(
                            new C506Reference()
                                    .withE1153(E1153ReferenceQualifier.ACE)
                                    .withE1154(referenceDocumentNum)
                    )
    );
}

// SG1.DTM
String referenceDocumentDate = invoicJson.getString("referenceDocumentDate");
if (!isEmpty(referenceDocumentDate)) {
    if (referenceSegGrp1 == null) {
        referenceSegGrp1 = new INVOIC.SegGrp1();
    }

    referenceSegGrp1.withDTM(
            new DTMDateTimePeriod()
                    .withC507(
                            new C507DateTimePeriod()
                                    .withE2005("171")
                                    .withE2380(referenceDocumentDate)
                                    .withE2379("102")
                    )
    );
}

if (referenceSegGrp1 != null) {
    invoic.withSegGrp1(referenceSegGrp1);
}

INVOIC.SegGrp1 referenceDownpaymentSegGrp1 = null;

// SG1.RFF
String referenceDownpaymentDocumentNum = invoicJson.getString("referenceDownpaymentDocumentNum");
if (!isEmpty(referenceDownpaymentDocumentNum)) {
    if (referenceDownpaymentSegGrp1 == null) {
        referenceDownpaymentSegGrp1 = new INVOIC.SegGrp1();
    }

    referenceDownpaymentSegGrp1.withRFF(
            new RFFReference()
                    .withC506(
                            new C506Reference()
                                    .withE1153(E1153ReferenceQualifier.ADE)
                                    .withE1154(referenceDownpaymentDocumentNum)
                    )
    );
}

// SG1.DTM
String referenceDownpaymentDocumentDate = invoicJson.getString("referenceDownpaymentDocumentDate");
if (!isEmpty(referenceDownpaymentDocumentDate)) {
    if (referenceDownpaymentSegGrp1 == null) {
        referenceDownpaymentSegGrp1 = new INVOIC.SegGrp1();
    }

    referenceDownpaymentSegGrp1.withDTM(
            new DTMDateTimePeriod()
                    .withC507(
                            new C507DateTimePeriod()
                                    .withE2005("171")
                                    .withE2380(referenceDownpaymentDocumentDate)
                                    .withE2379("102")
                    )
    );
}

if (referenceDownpaymentSegGrp1 != null) {
    invoic.withSegGrp1(referenceDownpaymentSegGrp1);
}

INVOIC.SegGrp2 buyerSegGrp2 = null;

// SG2.NAD
NADNameAndAddress buyerNAD = null;

String buyerCustomerId = invoicJson.getString("buyerCustomerId");
if (!isEmpty(buyerCustomerId)) {
    if (buyerSegGrp2 == null) {
        buyerSegGrp2 = new INVOIC.SegGrp2();
    }

    if (buyerNAD == null) {
        buyerNAD = new NADNameAndAddress();
        buyerNAD.withE3035(E3035PartyQualifier.BY);
    }

    String buyerEnhancedParty = invoicJson.getString("buyerEnhancedParty");
    if (!isEmpty(buyerEnhancedParty)) {
        buyerNAD.withC082(
                new C082PartyIdentificationDetails()
                        .withE3039(buyerCustomerId)
                        .withE1131(buyerEnhancedParty)
        );
    }

    String buyerCustomerName = invoicJson.getString("buyerCustomerName");
    if (!isEmpty(buyerCustomerName)) {
        buyerNAD.withC080(
                new C080PartyName()
                        .withE3036(buyerCustomerName)
        );
    }

    JSONArray buyerStreetInfos = invoicJson.getJSONArray("buyerStreetInfos");
    if (buyerStreetInfos != null && buyerStreetInfos.size() > 0) {
        buyerNAD.withC059(
                new C059Street()
                        .withE3042(buyerStreetInfos.toArray(new String[0]))
        );
    }

    String buyerCityName = invoicJson.getString("buyerCityName");
    if (!isEmpty(buyerCityName)) {
        buyerNAD.withE3164(buyerCityName);
    }

    String buyerPostalCode = invoicJson.getString("buyerPostalCode");
    if (!isEmpty(buyerPostalCode)) {
        buyerNAD.withE3251(buyerPostalCode);
    }

    String buyerCountry = invoicJson.getString("buyerCountry");
    if (!isEmpty(buyerCountry)) {
        buyerNAD.withE3207(buyerCountry);
    }

    buyerSegGrp2.withNAD(buyerNAD);

    String buyerVatRegistrationNum = invoicJson.getString("buyerVatRegistrationNum");
    if (!isEmpty(buyerVatRegistrationNum)) {
        buyerSegGrp2.withSegGrp3(
                new INVOIC.SegGrp2.SegGrp3()
                        .withRFF(
                                new RFFReference()
                                        .withC506(
                                                new C506Reference()
                                                        .withE1153(E1153ReferenceQualifier.VA)
                                                        .withE1154(buyerVatRegistrationNum)
                                        )
                        )
        );
    }

    String buyerAccountingUnitCode = invoicJson.getString("buyerAccountingUnitCode");
    if (!isEmpty(buyerAccountingUnitCode)) {
        buyerSegGrp2.withSegGrp5(
                new INVOIC.SegGrp2.SegGrp5()
                        .withCTA(
                                new CTAContactInformation()
                                        .withE3139(E3139ContactFunctionCoded.PD)
                                        .withC056(
                                                new C056DepartmentOrEmployeeDetails()
                                                        .withE3412(buyerAccountingUnitCode)
                                        )
                        )
        );
    }
}

if (buyerSegGrp2 != null) {
    invoic.withSegGrp2(buyerSegGrp2);
}

// SG2.NAD FII
INVOIC.SegGrp2 sellerSegGrp2 = null;
NADNameAndAddress sellerNAD = null;

String sellerVendorId = invoicJson.getString("sellerVendorId");
if (!isEmpty(sellerVendorId)) {
    if (sellerSegGrp2 == null) {
        sellerSegGrp2 = new INVOIC.SegGrp2();
    }

    if (sellerNAD == null) {
        sellerNAD = new NADNameAndAddress();
        sellerNAD.withE3035(E3035PartyQualifier.SE);
    }

    String sellerEnhancedParty = invoicJson.getString("sellerEnhancedParty");
    if (!isEmpty(sellerEnhancedParty)) {
        sellerNAD.withC082(
                new C082PartyIdentificationDetails()
                        .withE3039(sellerVendorId)
                        .withE1131(sellerEnhancedParty)
        );
    }

    String sellerVendorName = invoicJson.getString("sellerVendorName");
    if (!isEmpty(sellerVendorName)) {
        sellerNAD.withC080(
                new C080PartyName()
                        .withE3036(sellerVendorName)
        );
    }

    JSONArray sellerStreetInfos = invoicJson.getJSONArray("sellerStreetInfos");
    if (sellerStreetInfos != null && sellerStreetInfos.size() > 0) {
        sellerNAD.withC059(
                new C059Street()
                        .withE3042(sellerStreetInfos.toArray(new String[0]))
        );
    }

    String sellerCityName = invoicJson.getString("sellerCityName");
    if (!isEmpty(sellerCityName)) {
        sellerNAD.withE3164(sellerCityName);
    }

    String sellerPostalCode = invoicJson.getString("sellerPostalCode");
    if (!isEmpty(sellerPostalCode)) {
        sellerNAD.withE3251(sellerPostalCode);
    }

    String sellerCountry = invoicJson.getString("sellerCountry");
    if (!isEmpty(sellerCountry)) {
        sellerNAD.withE3207(sellerCountry);
    }

    sellerSegGrp2.withNAD(sellerNAD);

    FIIFinancialInstitutionInformation sellerFFI = null;

    String sellerBankAccount = invoicJson.getString("sellerBankAccount");
    if (!isEmpty(sellerBankAccount)) {
        if (sellerFFI == null) {
            sellerFFI = new FIIFinancialInstitutionInformation()
                    .withE3035(E3035PartyQualifier.BF);
        }

        sellerFFI.withC078(
                new C078AccountIdentification()
                        .withE3194(sellerBankAccount)
        );
    }

    String sellerBankName = invoicJson.getString("sellerBankName");
    String sellerInstitutionBranchNum = invoicJson.getString("sellerInstitutionBranchNum");
    if (!isEmpty(sellerBankName) && !isEmpty(sellerInstitutionBranchNum)) {
        if (sellerFFI == null) {
            sellerFFI = new FIIFinancialInstitutionInformation();
        }

        sellerFFI.withC088(
                new C088InstitutionIdentification()
                        .withE3434(sellerInstitutionBranchNum)
                        .withE3432(sellerBankName)
        );
    }

    if (sellerFFI != null) {
        sellerSegGrp2.withFII(sellerFFI);
    }

    String sellerVatRegistrationNum = invoicJson.getString("sellerVatRegistrationNum");
    if (!isEmpty(sellerVatRegistrationNum)) {
        sellerSegGrp2.withSegGrp3(
                new INVOIC.SegGrp2.SegGrp3()
                        .withRFF(
                                new RFFReference()
                                        .withC506(
                                                new C506Reference()
                                                        .withE1153(E1153ReferenceQualifier.VA)
                                                        .withE1154(sellerVatRegistrationNum)
                                        )
                        )
        );
    }

    CTAContactInformation sellerCTA = null;
    C056DepartmentOrEmployeeDetails sellerC056 = null;

    String sellerContactName = invoicJson.getString("sellerContactName");
    if (!isEmpty(sellerContactName)) {
        if (sellerCTA == null) {
            sellerCTA = new CTAContactInformation();
            sellerCTA.withE3139(E3139ContactFunctionCoded.AP);
        }

        if (sellerC056 == null) {
            sellerC056 = new C056DepartmentOrEmployeeDetails();
        }

        sellerC056.withE3412(sellerContactName);
        sellerCTA.withC056(sellerC056);
    }

    String sellerContactTel = invoicJson.getString("sellerContactTel");
    if (!isEmpty(sellerContactTel)) {
        if (sellerCTA == null) {
            sellerCTA = new CTAContactInformation();
            sellerCTA.withE3139(E3139ContactFunctionCoded.AP);
        }

        if (sellerC056 == null) {
            sellerC056 = new C056DepartmentOrEmployeeDetails();
        }

        sellerC056.withE3413(sellerContactTel);
        sellerCTA.withC056(sellerC056);
    }

    if (sellerCTA != null) {
        sellerSegGrp2.withSegGrp5(
                new INVOIC.SegGrp2.SegGrp5().withCTA(sellerCTA)
        );
    }
}

if (sellerSegGrp2 != null) {
    invoic.withSegGrp2(sellerSegGrp2);
}

// SG2.NAD
INVOIC.SegGrp2 invoiceIssuerSegGrp2 = null;
NADNameAndAddress invoiceIssuerNAD = null;

String invoiceIssuerId = invoicJson.getString("invoiceIssuerId");
if (!isEmpty(invoiceIssuerId)) {
    if (invoiceIssuerSegGrp2 == null) {
        invoiceIssuerSegGrp2 = new INVOIC.SegGrp2();
    }

    if (invoiceIssuerNAD == null) {
        invoiceIssuerNAD = new NADNameAndAddress();
        invoiceIssuerNAD.withE3035(E3035PartyQualifier.II);
    }

    String invoiceIssuerEnhancedParty = invoicJson.getString("invoiceIssuerEnhancedParty");
    if (!isEmpty(invoiceIssuerEnhancedParty)) {
        invoiceIssuerNAD.withC082(
                new C082PartyIdentificationDetails()
                        .withE3039(invoiceIssuerId)
                        .withE1131(invoiceIssuerEnhancedParty)
        );
    }

    String invoiceIssuerName = invoicJson.getString("invoiceIssuerName");
    if (!isEmpty(invoiceIssuerName)) {
        invoiceIssuerNAD.withC080(
                new C080PartyName()
                        .withE3036(invoiceIssuerName)
        );
    }

    JSONArray invoiceIssuerStreetInfos = invoicJson.getJSONArray("invoiceIssuerStreetInfos");
    if (invoiceIssuerStreetInfos != null && invoiceIssuerStreetInfos.size() > 0) {
        invoiceIssuerNAD.withC059(
                new C059Street()
                        .withE3042(invoiceIssuerStreetInfos.toArray(new String[0]))
        );
    }

    String invoiceIssuerCityName = invoicJson.getString("invoiceIssuerCityName");
    if (!isEmpty(invoiceIssuerCityName)) {
        invoiceIssuerNAD.withE3164(invoiceIssuerCityName);
    }

    String invoiceIssuerPostalCode = invoicJson.getString("invoiceIssuerPostalCode");
    if (!isEmpty(invoiceIssuerPostalCode)) {
        invoiceIssuerNAD.withE3251(invoiceIssuerPostalCode);
    }

    String invoiceIssuerCountry = invoicJson.getString("invoiceIssuerCountry");
    if (!isEmpty(invoiceIssuerCountry)) {
        invoiceIssuerNAD.withE3207(invoiceIssuerCountry);
    }

    if (invoiceIssuerNAD != null) {
        invoiceIssuerSegGrp2.withNAD(invoiceIssuerNAD);
    }

    String invoiceIssuerVatRegistrationNum = invoicJson.getString("invoiceIssuerVatRegistrationNum");
    if (!isEmpty(invoiceIssuerVatRegistrationNum)) {
        invoiceIssuerSegGrp2.withSegGrp3(
                new INVOIC.SegGrp2.SegGrp3()
                        .withRFF(
                                new RFFReference()
                                        .withC506(
                                                new C506Reference()
                                                        .withE1153(E1153ReferenceQualifier.VA)
                                                        .withE1154(invoiceIssuerVatRegistrationNum)
                                        )
                        )
        );
    }
}

if (invoiceIssuerSegGrp2 != null) {
    invoic.withSegGrp2(invoiceIssuerSegGrp2);
}

// SG2.NAD
INVOIC.SegGrp2 factorSegGrp2 = null;
NADNameAndAddress factorNAD = null;

String factorId = invoicJson.getString("factorId");
if (!isEmpty(factorId)) {
    if (factorSegGrp2 == null) {
        factorSegGrp2 = new INVOIC.SegGrp2();
    }

    if (factorNAD == null) {
        factorNAD = new NADNameAndAddress();
        factorNAD.withE3035(E3035PartyQualifier.RB);
    }

    String factorEnhancedParty = invoicJson.getString("factorEnhancedParty");
    if (!isEmpty(factorEnhancedParty)) {
        factorNAD.withC082(
                new C082PartyIdentificationDetails()
                        .withE3039(factorId)
                        .withE1131(factorEnhancedParty)
        );
    }

    String factorName = invoicJson.getString("factorName");
    if (!isEmpty(factorName)) {
        factorNAD.withC080(
                new C080PartyName()
                        .withE3036(factorName)
        );
    }

    JSONArray factorStreetInfos = invoicJson.getJSONArray("factorStreetInfos");
    if (factorStreetInfos != null && factorStreetInfos.size() > 0) {
        factorNAD.withC059(
                new C059Street()
                        .withE3042(factorStreetInfos.toArray(new String[0]))
        );
    }

    String factorCityName = invoicJson.getString("factorCityName");
    if (!isEmpty(factorCityName)) {
        factorNAD.withE3164(factorCityName);
    }

    String factorPostalCode = invoicJson.getString("factorPostalCode");
    if (!isEmpty(factorPostalCode)) {
        factorNAD.withE3251(factorPostalCode);
    }

    String factorCountry = invoicJson.getString("factorCountry");
    if (!isEmpty(factorCountry)) {
        factorNAD.withE3207(factorCountry);
    }

    factorSegGrp2.withNAD(factorNAD);

    String factorVatRegistrationNum = invoicJson.getString("factorVatRegistrationNum");
    if (!isEmpty(factorVatRegistrationNum)) {
        factorSegGrp2.withSegGrp3(
                new INVOIC.SegGrp2.SegGrp3()
                        .withRFF(
                                new RFFReference()
                                        .withC506(
                                                new C506Reference()
                                                        .withE1153(E1153ReferenceQualifier.VA)
                                                        .withE1154(factorVatRegistrationNum)
                                        )
                        )
        );
    }
}

if (factorSegGrp2 != null) {
    invoic.withSegGrp2(factorSegGrp2);
}

// SG6.TAX
INVOIC.SegGrp6 taxSegGrp6 = null;
TAXDutyTaxFeeDetails taxDetails = null;

String taxType = invoicJson.getString("taxType");
if (!isEmpty(taxType)) {
    if (taxSegGrp6 == null) {
        taxSegGrp6 = new INVOIC.SegGrp6();
    }

    if (taxDetails == null) {
        taxDetails = new TAXDutyTaxFeeDetails().withE5283(taxType);
    }

    taxDetails.withC241(
            new C241DutyTaxFeeType()
//                                                            .withE5152(taxType)
                    .withE5153(E5153DutyTaxFeeTypeCoded.VAT)
    );

    String taxRule = invoicJson.getString("taxRule");
    if (!isEmpty(taxRule)) {
        taxDetails.withC533(
                new C533DutyTaxFeeAccountDetail()
                        .withE5289(taxRule)
        );
    }

    taxSegGrp6.withTAX(taxDetails);
}

if (taxSegGrp6 != null) {
    invoic.withSegGrp6(taxSegGrp6);
}

//SG7.CUX
INVOIC.SegGrp7 invoicSegGrp7 = null;

String invoiceCurrency = invoicJson.getString("invoiceCurrency");
if (!isEmpty(invoiceCurrency)) {
    if (invoicSegGrp7 == null) {
        invoicSegGrp7 = new INVOIC.SegGrp7();
    }

    invoicSegGrp7.withCUX(
            new CUXCurrencies()
                    .withC504(
                            new C504CurrencyDetails()
                                    .withE6347("2")
                                    .withE6345(invoiceCurrency)
                    )
    );
}

String targetCurrency = invoicJson.getString("targetCurrency");
if (!isEmpty(targetCurrency)) {
    if (invoicSegGrp7 == null) {
        invoicSegGrp7 = new INVOIC.SegGrp7();
    }

    invoicSegGrp7.withCUX(
            new CUXCurrencies()
                    .withC504(
                            new C504CurrencyDetails()
                                    .withE6347("3")
                                    .withE6345(targetCurrency)
                    )
    );
}

BigDecimal exchangeRate = invoicJson.getBigDecimal("exchangeRate");
if (exchangeRate != null) {
    if (invoicSegGrp7 == null) {
        invoicSegGrp7 = new INVOIC.SegGrp7();
    }

    invoicSegGrp7.withCUX(
            new CUXCurrencies()
                    .withE5402(exchangeRate)
    );
}

String exchangeRateDate = invoicJson.getString("exchangeRateDate");
if (!isEmpty(exchangeRateDate)) {
    if (invoicSegGrp7 == null) {
        invoicSegGrp7 = new INVOIC.SegGrp7();
    }

    invoicSegGrp7.withDTM(
            new DTMDateTimePeriod()
                    .withC507(
                            new C507DateTimePeriod()
                                    .withE2005("134")
                                    .withE2380(exchangeRateDate)
                                    .withE2379("102")
                    )
    );
}

if (invoicSegGrp7 != null) {
    invoic.withSegGrp7(invoicSegGrp7);
}

// SG8.PAT DTM
INVOIC.SegGrp8 paymentSegGrp8 = null;
PATPaymentTermsBasis paymentPAT = null;

String paymentTermsType = invoicJson.getString("paymentTermsType");
if (!isEmpty(paymentTermsType)) {
    if (paymentSegGrp8 == null) {
        paymentSegGrp8 = new INVOIC.SegGrp8();
    }

    if (paymentPAT == null) {
        paymentPAT = new PATPaymentTermsBasis().withE4279(paymentTermsType);
    }

    C110PaymentTerms paymentC110 = null;

    String paymentTermsIdentification = invoicJson.getString("paymentTermsIdentification");
    if (!isEmpty(paymentTermsIdentification)) {
        if (paymentC110 == null) {
            paymentC110 = new C110PaymentTerms();
        }

        paymentC110.withE4277(paymentTermsIdentification);
    }

    String paymentTerms = invoicJson.getString("paymentTerms");
    if (!isEmpty(paymentTerms)) {
        if (paymentC110 == null) {
            paymentC110 = new C110PaymentTerms();
        }

        paymentC110.withE4276(paymentTerms);
    }

    if (paymentC110 != null) {
        paymentPAT.withC110(paymentC110);
    }

    C112TermsTimeInformation paymentC112 = null;

    String paymentReferenceDate = invoicJson.getString("paymentReferenceDate");
    if (!isEmpty(paymentReferenceDate)) {
        if (paymentC112 == null) {
            paymentC112 = new C112TermsTimeInformation();
        }

        paymentC112.withE2475(paymentReferenceDate);
    }

    String paymentTermsCalculation = invoicJson.getString("paymentTermsCalculation");
    if (!isEmpty(paymentTermsCalculation)) {
        if (paymentC112 == null) {
            paymentC112 = new C112TermsTimeInformation();
        }

        paymentC112.withE2009(paymentTermsCalculation);
    }

    String paymentPeriodType = invoicJson.getString("paymentPeriodType");
    if (!isEmpty(paymentPeriodType)) {
        if (paymentC112 == null) {
            paymentC112 = new C112TermsTimeInformation();
        }

        paymentC112.withE2151(paymentPeriodType);
    }

    BigDecimal paymentPeriodUnitNum = invoicJson.getBigDecimal("paymentPeriodUnitNum");
    if (paymentPeriodUnitNum != null) {
        if (paymentC112 == null) {
            paymentC112 = new C112TermsTimeInformation();
        }

        paymentC112.withE2152(paymentPeriodUnitNum);
    }

    if (paymentC112 != null) {
        paymentPAT.withC112(paymentC112);
    }

    if (paymentPAT != null) {
        paymentSegGrp8.withPAT(paymentPAT);
    }

    String paymentDate = invoicJson.getString("paymentDate");
    if (!isEmpty(paymentDate)) {
        paymentSegGrp8.withDTM(
                new DTMDateTimePeriod()
                        .withC507(
                                new C507DateTimePeriod()
                                        .withE2005("138")
                                        .withE2380(paymentDate)
                                        .withE2379("102")
                        )
        );
    }
}

if (paymentSegGrp8 != null) {
    invoic.withSegGrp8(paymentSegGrp8);
}

// SG15.ALC SG18.PCD SG19.MOA SG20.RTE
INVOIC.SegGrp15 alcSegGrp15 = null;

String allowanceOrCharge = invoicJson.getString("allowanceOrCharge");
if (!isEmpty(allowanceOrCharge)) {
    if (alcSegGrp15 == null) {
        alcSegGrp15 = new INVOIC.SegGrp15();
    }

    ALCAllowanceOrCharge alcAllowanceOrCharge = new ALCAllowanceOrCharge()
            .withE5463(E5463AllowanceOrChargeQualifier.fromValue(allowanceOrCharge))
            .withC552(
                    new C552AllowanceChargeInformation()
                            .withE1230(allowanceOrCharge)
            );

    String allowanceOrChargeIterationNum = invoicJson.getString("allowanceOrChargeIterationNum");
    if (!isEmpty(allowanceOrChargeIterationNum)) {
        alcAllowanceOrCharge.withE1227(allowanceOrChargeIterationNum);
    }

    alcSegGrp15.withALC(alcAllowanceOrCharge);

    BigDecimal allowanceOrChargeRate = invoicJson.getBigDecimal("allowanceOrChargeRate");
    if (allowanceOrChargeRate != null) {
        alcSegGrp15.withSegGrp18(
                new INVOIC.SegGrp15.SegGrp18()
                        .withPCD(
                                new PCDPercentageDetails()
                                        .withC501(
                                                new C501PercentageDetails()
                                                        .withE5482(allowanceOrChargeRate)
                                        )
                        )
        );
    }

    INVOIC.SegGrp15.SegGrp19 alcSegGrp19 = null;

    BigDecimal allowanceOrChargeAmount = invoicJson.getBigDecimal("allowanceOrChargeAmount");
    if (allowanceOrChargeAmount != null) {
        if (alcSegGrp19 == null) {
            alcSegGrp19 = new INVOIC.SegGrp15.SegGrp19();
        }

        alcSegGrp19.withMOA(
                new MOAMonetaryAmount()
                        .withC516(
                                new C516MonetaryAmount()
                                        .withE5004(allowanceOrChargeAmount)
                        )
        );
    }

    BigDecimal allowanceOrChargeUnit = invoicJson.getBigDecimal("allowanceOrChargeUnit");
    if (allowanceOrChargeUnit != null) {
        if (alcSegGrp19 == null) {
            alcSegGrp19 = new INVOIC.SegGrp15.SegGrp19();
        }

        alcSegGrp19.withMOA(
                new MOAMonetaryAmount()
                        .withC516(
                                new C516MonetaryAmount()
                                        .withE5004(allowanceOrChargeUnit)
                        )
        );
    }

    if (alcSegGrp19 != null) {
        alcSegGrp15.withSegGrp19(alcSegGrp19);
    }

    BigDecimal allowanceOrChargePerQuantityAmount = invoicJson.getBigDecimal("allowanceOrChargePerQuantityAmount");
    if (allowanceOrChargePerQuantityAmount != null) {
        alcSegGrp15.withSegGrp20(
                new INVOIC.SegGrp15.SegGrp20()
                        .withRTE(
                                new RTERateDetails()
                                        .withC128(
                                                new C128RateDetails()
                                                        .withE5420(allowanceOrChargePerQuantityAmount)
                                        )
                        )
        );
    }
}

if (alcSegGrp15 != null) {
    invoic.withSegGrp15(alcSegGrp15);
}

JSONArray docDetails = invoicJson.getJSONArray("docDetails");
for (int i = 0; i < docDetails.size(); i++) {
    JSONObject doc = docDetails.getJSONObject(i);

    if (doc != null) {
        INVOIC.SegGrp25 docSegGrp25 = null;

        // SG25.LIN SG25.PIA SG25.IMD SG25.QTY SG25.FTX SG26.MOA SG28.PRI SG29.RFF SG33.TAX
        BigDecimal docLineNum = doc.getBigDecimal("docLineNum");
        if (docLineNum != null) {
            if (docSegGrp25 == null) {
                docSegGrp25 = new INVOIC.SegGrp25();
            }

            JSONArray items = doc.getJSONArray("items");
            if (items != null && items.size() > 0) {
                PIAAdditionalProductId[] piaAdditionalProductIds = new PIAAdditionalProductId[items.size()];
                for (int j = 0; j < items.size(); j++) {
                    JSONObject item = items.getJSONObject(j);

                    if (item.containsKey("itemNum") && item.containsKey("itemType")) {
                        String itemNum = item.getString("itemNum");
                        String itemType = item.getString("itemType");

                        if (j == 0) {
                            docSegGrp25.withLIN(
                                    new LINLineItem()
                                            .withE1082(docLineNum)
                                            .withC212(
                                                    new C212ItemNumberIdentification()
                                                            .withE7140(itemNum)
                                                            .withE7143(E7143ItemNumberTypeCoded.fromValue(itemType))
                                            )
                            );
                        } else {
                            PIAAdditionalProductId piaAdditionalProductId = new PIAAdditionalProductId()
                                    .withE4347("1")
                                    .withC212(
                                            new C212ItemNumberIdentification()
                                                    .withE7140(itemNum)
                                                    .withE7143(E7143ItemNumberTypeCoded.fromValue(itemType))
                                    );
                            piaAdditionalProductIds[j] = piaAdditionalProductId;
                        }
                    }
                }

                docSegGrp25.withPIA(
                        piaAdditionalProductIds
                );
            }

            String itemDesc = doc.getString("itemDesc");
            if (!isEmpty(itemDesc)) {
                docSegGrp25.withIMD(
                        new IMDItemDescription()
                                .withC273(
                                        new C273ItemDescription()
                                                .withE7008(itemDesc)
                                )
                );
            }

            BigDecimal quantity = doc.getBigDecimal("quantity");
            String quantityUnit = doc.getString("quantityUnit");
            if (quantity != null && !isEmpty(quantityUnit)) {
                docSegGrp25.withQTY(
                        new QTYQuantity()
                                .withC186(
                                        new C186QuantityDetails()
                                                .withE6063("47")
                                                .withE6060(quantity)
                                                .withE6411(quantityUnit)
                                )
                );
            }

            JSONArray serviceDeliveryInfos = doc.getJSONArray("serviceDeliveryInfos");
            if (serviceDeliveryInfos != null && serviceDeliveryInfos.size() > 0) {
                docSegGrp25.withFTX(
                        new FTXFreeText()
                                .withE4451(E4451TextSubjectQualifier.ACF)
                                .withC108(
                                        new C108TextLiteral()
                                                .withE4440(serviceDeliveryInfos.toArray(new String[0]))
                                )
                );
            }

            JSONArray generalInfos = doc.getJSONArray("generalInfos");
            if (generalInfos != null && generalInfos.size() > 0) {
                docSegGrp25.withFTX(
                        new FTXFreeText()
                                .withE4451(E4451TextSubjectQualifier.AAI)
                                .withC108(
                                        new C108TextLiteral()
                                                .withE4440(generalInfos.toArray(new String[0]))
                                )
                );
            }

            BigDecimal taxableAmount = doc.getBigDecimal("taxableAmount");
            if (taxableAmount != null) {
                docSegGrp25.withSegGrp26(
                        new INVOIC.SegGrp25.SegGrp26()
                                .withMOA(
                                        new MOAMonetaryAmount()
                                                .withC516(
                                                        new C516MonetaryAmount()
                                                                .withE5025("125")
                                                                .withE5004(taxableAmount)
                                                )
                                )
                );
            }

            BigDecimal vatAmount = doc.getBigDecimal("vatAmount");
            if (vatAmount != null) {
                docSegGrp25.withSegGrp26(
                        new INVOIC.SegGrp25.SegGrp26()
                                .withMOA(
                                        new MOAMonetaryAmount()
                                                .withC516(
                                                        new C516MonetaryAmount()
                                                                .withE5025("150")
                                                                .withE5004(vatAmount)
                                                )
                                )
                );
            }

            BigDecimal unitNetPrice = doc.getBigDecimal("unitNetPrice");
            String unitNetPriceType = doc.getString("unitNetPriceType");
            if (unitNetPrice != null && !isEmpty(unitNetPriceType)) {
                docSegGrp25.withSegGrp28(
                        new INVOIC.SegGrp25.SegGrp28()
                                .withPRI(
                                        new PRIPriceDetails()
                                                .withC509(
                                                        new C509PriceInformation()
                                                                .withE5125(E5125PriceQualifier.CAL)
                                                                .withE5118(unitNetPrice)
                                                                .withE5387(E5387PriceTypeQualifier.valueOf(unitNetPriceType))
                                                )
                                )
                );
            }

            BigDecimal grossUnitPrice = doc.getBigDecimal("grossUnitPrice");
            String grossUnitPriceType = doc.getString("unitNetPriceType");
            if (grossUnitPrice != null && !isEmpty(grossUnitPriceType)) {
                docSegGrp25.withSegGrp28(
                        new INVOIC.SegGrp25.SegGrp28()
                                .withPRI(
                                        new PRIPriceDetails()
                                                .withC509(
                                                        new C509PriceInformation()
                                                                .withE5125(E5125PriceQualifier.AAB)
                                                                .withE5118(grossUnitPrice)
                                                                .withE5387(E5387PriceTypeQualifier.valueOf(grossUnitPriceType))
                                                )
                                )
                );
            }

            String customerPurchaseOrderNum = doc.getString("customerPurchaseOrderNum");
            if (!isEmpty(customerPurchaseOrderNum)) {
                docSegGrp25.withSegGrp29(
                        new INVOIC.SegGrp25.SegGrp29()
                                .withRFF(
                                        new RFFReference()
                                                .withC506(
                                                        new C506Reference()
                                                                .withE1153(E1153ReferenceQualifier.LI)
                                                                .withE1154(customerPurchaseOrderNum)
                                                )
                                )
                );
            }

            String deliveryOrder = doc.getString("deliveryOrder");
            String deliveryDate = doc.getString("deliveryDate");
            if (!isEmpty(deliveryOrder) && !isEmpty(deliveryDate)) {
                docSegGrp25.withSegGrp29(
                        new INVOIC.SegGrp25.SegGrp29()
                                .withRFF(
                                        new RFFReference()
                                                .withC506(
                                                        new C506Reference()
                                                                .withE1153(E1153ReferenceQualifier.DQ)
                                                                .withE1154(deliveryOrder)
                                                )
                                )
                                .withDTM(
                                        new DTMDateTimePeriod()
                                                .withC507(
                                                        new C507DateTimePeriod()
                                                                .withE2005("171")
                                                                .withE2380(deliveryDate)
                                                                .withE2379("102")
                                                )
                                )
                );
            }

            JSONArray taxInfos = doc.getJSONArray("taxInfos");
            if (taxInfos != null && taxInfos.size() > 0) {
                TAXDutyTaxFeeDetails[] taxDutyTaxFeeDetails = new TAXDutyTaxFeeDetails[taxInfos.size()];
                for (int k = 0; k < taxInfos.size(); k++) {
                    JSONObject taxInfo = taxInfos.getJSONObject(k);

                    String _taxType = taxInfo.getString("taxType");
                    String _taxRule = taxInfo.getString("taxRule");
                    String _taxRate = taxInfo.getString("taxRate");

                    taxDutyTaxFeeDetails[k] = new TAXDutyTaxFeeDetails()
                            .withE5283("7")
                            .withC241(
                                    new C241DutyTaxFeeType()
                                            .withE5153(E5153DutyTaxFeeTypeCoded.valueOf(_taxType))
                            )
                            .withC533(
                                    new C533DutyTaxFeeAccountDetail()
                                            .withE5289(_taxRule)
                            )
                            .withC243(
                                    new C243DutyTaxFeeDetail()
                                            .withE5278(_taxRate)
                            );
                }

                if (taxDutyTaxFeeDetails.length == 1) {
                    docSegGrp25.withSegGrp33(
                            new INVOIC.SegGrp25.SegGrp33()
                                    .withTAX(
                                            taxDutyTaxFeeDetails[0]
                                    )
                    );
                } else if (taxDutyTaxFeeDetails.length > 1) {
                    docSegGrp25.withSegGrp33(
                            new INVOIC.SegGrp25.SegGrp33()
                                    .withTAX(taxDutyTaxFeeDetails[0])
                                    .withTAX(taxDutyTaxFeeDetails[1])
                    );
                }
            }
        }

        if (docSegGrp25 != null) {
            invoic.withSegGrp25(docSegGrp25);
        }

        // SG40.PCD SG41.MOA SG42.RTE
        INVOIC.SegGrp25 docAlcSegGrp25 = null;

        String _allowanceOrCharge = doc.getString("allowanceOrCharge");
        if (!isEmpty(_allowanceOrCharge)) {
            if (docAlcSegGrp25 == null) {
                docAlcSegGrp25 = new INVOIC.SegGrp25();
            }

            INVOIC.SegGrp25.SegGrp38 segGrp38 = new INVOIC.SegGrp25.SegGrp38();

            String _allowanceOrChargeIterationNum = doc.getString("allowanceOrChargeIterationNum");
            if (!isEmpty(_allowanceOrChargeIterationNum)) {
                segGrp38.withALC(
                        new ALCAllowanceOrCharge()
                                .withE5463(E5463AllowanceOrChargeQualifier.fromValue(_allowanceOrCharge))
                                .withC552(
                                        new C552AllowanceChargeInformation()
                                                .withE1230(_allowanceOrCharge)
                                )
                                .withE1227(_allowanceOrChargeIterationNum)
                );
            }

            BigDecimal _allowanceOrChargeRate = doc.getBigDecimal("allowanceOrChargeRate");
            if (_allowanceOrChargeRate != null) {
                segGrp38.withSegGrp40(
                        new INVOIC.SegGrp25.SegGrp38.SegGrp40()
                                .withPCD(
                                        new PCDPercentageDetails()
                                                .withC501(
                                                        new C501PercentageDetails()
                                                                .withE5482(_allowanceOrChargeRate)
                                                )
                                )
                );
            }

            BigDecimal _allowanceOrChargeAmount = doc.getBigDecimal("allowanceOrChargeAmount");
            if (_allowanceOrChargeAmount != null) {
                segGrp38.withSegGrp41(
                        new INVOIC.SegGrp25.SegGrp38.SegGrp41()
                                .withMOA(
                                        new MOAMonetaryAmount()
                                                .withC516(
                                                        new C516MonetaryAmount()
                                                                .withE5025("8")
                                                                .withE5004(_allowanceOrChargeAmount)
                                                )
                                )
                );
            }

            BigDecimal _allowanceOrChargePerQuantityAmount = doc.getBigDecimal("allowanceOrChargePerQuantityAmount");
            if (_allowanceOrChargePerQuantityAmount != null) {
                segGrp38.withSegGrp42(
                        new INVOIC.SegGrp25.SegGrp38.SegGrp42()
                                .withRTE(
                                        new RTERateDetails()
                                                .withC128(
                                                        new C128RateDetails()
                                                                .withE5420(_allowanceOrChargePerQuantityAmount)
                                                )
                                )
                );
            }

            docAlcSegGrp25.withSegGrp38(segGrp38);
        }

        if (docAlcSegGrp25 != null) {
            invoic.withSegGrp25(docAlcSegGrp25);
        }
    }
}

invoic.withUNS(
        new UNSSectionControl()
                .withE0081(E0081SectionIdentification.S)
);

// SG48.MOA
INVOIC.SegGrp48 totalTaxableAmountSegGrp48 = null;

BigDecimal totalTaxableAmount = invoicJson.getBigDecimal("totalTaxableAmount");

// TODO
if (totalTaxableAmount != null) {
    if (totalTaxableAmountSegGrp48 == null) {
        totalTaxableAmountSegGrp48 = new INVOIC.SegGrp48();
    }

    totalTaxableAmountSegGrp48.withMOA(
            new MOAMonetaryAmount()
                    .withC516(
                            new C516MonetaryAmount()
                                    .withE5025("125")
                                    .withE5004(totalTaxableAmount)
                    )
    );
}

if (totalTaxableAmountSegGrp48 != null) {
    invoic.withSegGrp48(totalTaxableAmountSegGrp48);
}

INVOIC.SegGrp48 totalTaxAmountSegGrp48 = null;

// TODO
BigDecimal totalTaxAmount = invoicJson.getBigDecimal("totalTaxAmount");
if (totalTaxAmount != null) {
    if (totalTaxAmountSegGrp48 == null) {
        totalTaxAmountSegGrp48 = new INVOIC.SegGrp48();
    }

    totalTaxAmountSegGrp48.withMOA(
            new MOAMonetaryAmount()
                    .withC516(
                            new C516MonetaryAmount()
                                    .withE5025("124")
                                    .withE5004(totalTaxAmount)
                    )
    );
}

if (totalTaxAmountSegGrp48 != null) {
    invoic.withSegGrp48(totalTaxAmountSegGrp48);
}

INVOIC.SegGrp48 totalAmountSegGrp48 = null;

// TODO
BigDecimal totalAmount = invoicJson.getBigDecimal("totalAmount");
if (totalAmount != null) {
    if (totalAmountSegGrp48 == null) {
        totalAmountSegGrp48 = new INVOIC.SegGrp48();
    }

    totalAmountSegGrp48.withMOA(
            new MOAMonetaryAmount()
                    .withC516(
                            new C516MonetaryAmount()
                                    .withE5025("128")
                                    .withE5004(totalAmount)
                    )
    );
}

if (totalAmountSegGrp48 != null) {
    invoic.withSegGrp48(totalAmountSegGrp48);
}

INVOIC.SegGrp48 downpaymentTotalAmountSegGrp48 = null;

BigDecimal downpaymentTotalAmount = invoicJson.getBigDecimal("downpaymentTotalAmount");
if (downpaymentTotalAmount != null) {
    if (downpaymentTotalAmountSegGrp48 == null) {
        downpaymentTotalAmountSegGrp48 = new INVOIC.SegGrp48();
    }

    downpaymentTotalAmountSegGrp48.withMOA(
            new MOAMonetaryAmount()
                    .withC516(
                            new C516MonetaryAmount()
                                    .withE5025("113")
                                    .withE5004(downpaymentTotalAmount)
                    )
    );
}

if (downpaymentTotalAmountSegGrp48 != null) {
    invoic.withSegGrp48(downpaymentTotalAmountSegGrp48);
}

INVOIC.SegGrp48 downpaymentTaxableAmountSegGrp48 = null;

BigDecimal downpaymentTaxableAmount = invoicJson.getBigDecimal("downpaymentTaxableAmount");
if (downpaymentTaxableAmount != null) {
    if (downpaymentTaxableAmountSegGrp48 == null) {
        downpaymentTaxableAmountSegGrp48 = new INVOIC.SegGrp48();
    }

    downpaymentTaxableAmountSegGrp48.withMOA(
            new MOAMonetaryAmount()
                    .withC516(
                            new C516MonetaryAmount()
                                    .withE5025("165")
                                    .withE5004(downpaymentTaxableAmount)
                    )
    );
}

if (downpaymentTaxableAmountSegGrp48 != null) {
    invoic.withSegGrp48(downpaymentTaxableAmountSegGrp48);
}

INVOIC.SegGrp48 payableAmountSegGrp48 = null;

BigDecimal payableAmount = invoicJson.getBigDecimal("payableAmount");
if (payableAmount != null) {
    if (payableAmountSegGrp48 == null) {
        payableAmountSegGrp48 = new INVOIC.SegGrp48();
    }

    payableAmountSegGrp48.withMOA(
            new MOAMonetaryAmount()
                    .withC516(
                            new C516MonetaryAmount()
                                    .withE5025("9")
                                    .withE5004(payableAmount)
                    )
    );
}

if (payableAmountSegGrp48 != null) {
    invoic.withSegGrp48(payableAmountSegGrp48);
}

INVOIC.SegGrp48 totalVatAmountSegGrp48 = null;

BigDecimal totalVatAmount = invoicJson.getBigDecimal("totalVatAmount");
if (totalVatAmount != null) {
    if (totalVatAmountSegGrp48 == null) {
        totalVatAmountSegGrp48 = new INVOIC.SegGrp48();
    }

    totalVatAmountSegGrp48.withMOA(
            new MOAMonetaryAmount()
                    .withC516(
                            new C516MonetaryAmount()
                                    .withE5025("ZZZ")
                                    .withE5004(totalVatAmount)
                    )
    );
}

if (totalVatAmountSegGrp48 != null) {
    invoic.withSegGrp48(totalVatAmountSegGrp48);
}

INVOIC.SegGrp50 segGrp50 = null;

String taxTypeCode = invoicJson.getString("taxTypeCode");
if (!isEmpty(taxTypeCode)) {
    if (segGrp50 == null) {
        segGrp50 = new INVOIC.SegGrp50();
    }

    TAXDutyTaxFeeDetails taxDutyTaxFeeDetails = new TAXDutyTaxFeeDetails().withE5283("7");
    C241DutyTaxFeeType c241DutyTaxFeeType = new C241DutyTaxFeeType();
    c241DutyTaxFeeType.withE5153(E5153DutyTaxFeeTypeCoded.valueOf(taxTypeCode));

    String currentTaxDesc = invoicJson.getString("currentTaxDesc");
    if (!isEmpty(currentTaxDesc)) {
        c241DutyTaxFeeType.withE5152(currentTaxDesc);
    }

    String currentTaxAssessmentBasis = invoicJson.getString("currentTaxAssessmentBasis");
    if (!isEmpty(currentTaxAssessmentBasis)) {
        taxDutyTaxFeeDetails.withE5286(currentTaxAssessmentBasis);
    }

    String currentTaxRate = invoicJson.getString("currentTaxRate");
    if (!isEmpty(currentTaxRate)) {
        taxDutyTaxFeeDetails.withC243(
                new C243DutyTaxFeeDetail()
                        .withE5278(currentTaxRate)
        );
    }

    taxDutyTaxFeeDetails.withC241(c241DutyTaxFeeType);
    segGrp50.withTAX(taxDutyTaxFeeDetails);
}

BigDecimal addedTaxAmount = invoicJson.getBigDecimal("addedTaxAmount");
if (addedTaxAmount != null) {
    if (segGrp50 == null) {
        segGrp50 = new INVOIC.SegGrp50();
    }

    segGrp50.withMOA(
            new MOAMonetaryAmount()
                    .withC516(
                            new C516MonetaryAmount()
                                    .withE5025("150")
                                    .withE5004(addedTaxAmount)
                    )
    );
}

BigDecimal otherTaxAmount = invoicJson.getBigDecimal("otherTaxAmount");
if (otherTaxAmount != null) {
    if (segGrp50 == null) {
        segGrp50 = new INVOIC.SegGrp50();
    }

    segGrp50.withMOA(
            new MOAMonetaryAmount()
                    .withC516(
                            new C516MonetaryAmount()
                                    .withE5025("124")
                                    .withE5004(otherTaxAmount)
                    )
    );
}

if (segGrp50 != null) {
    invoic.withSegGrp50(segGrp50);
}

INVOIC.SegGrp51 segGrp51 = null;

String totalAllowanceOrCharge = invoicJson.getString("totalAllowanceOrCharge");
if (!isEmpty(totalAllowanceOrCharge)) {
    if (segGrp51 == null) {
        segGrp51 = new INVOIC.SegGrp51();
    }

    segGrp51.withALC(
            new ALCAllowanceOrCharge()
                    .withE5463(E5463AllowanceOrChargeQualifier.fromValue(totalAllowanceOrCharge))
                    .withC552(
                            new C552AllowanceChargeInformation()
                                    .withE1230(totalAllowanceOrCharge)
                    )
    );
}

BigDecimal totalDiscountOrChargeAmount = invoicJson.getBigDecimal("totalDiscountOrChargeAmount");
if (totalDiscountOrChargeAmount != null) {
    if (segGrp51 == null) {
        segGrp51 = new INVOIC.SegGrp51();
    }

    segGrp51.withMOA(
            new MOAMonetaryAmount()
                    .withC516(
                            new C516MonetaryAmount()
                                    .withE5025("8")
                                    .withE5004(totalDiscountOrChargeAmount)
                    )
    );
}

if (segGrp51 != null) {
    invoic.withSegGrp51(segGrp51);
}

JAXBElement invoiceEle = new JAXBElement<>(new QName("http://www.ibm.com/dfdl/edi/un/edifact/D96A", "INVOIC", "D96A"), INVOIC.class, invoic);

message.withContent(invoiceEle);

String messageSegments = invoicJson.getString("messageSegments");
String tailMessageReferenceNum = invoicJson.getString("tailMessageReferenceNum");

if (!isEmpty(messageSegments) && !isEmpty(tailMessageReferenceNum)) {
    message.withContent(
            new JAXBElement<>(new QName("UNT"), UNTMessageTrailer.class,
                    new UNTMessageTrailer()
                            .withE0074(new BigDecimal(Double.valueOf(messageSegments)))
                            .withE0062(tailMessageReferenceNum))
    );
}

interchange.withMessage(message);

interchange.withUNZ(
        new UNZInterchangeTrailer()
                .withE0036(new BigDecimal(1))
                .withE0020("17")
);

// Turn Java model into XML
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
//JAXBContext jaxbContext = JAXBContext.newInstance(Interchange.class, org.smooks.edifact.binding.service.ObjectFactory.class, org.smooks.edifact.binding.d03b.ObjectFactory.class);
//jaxbContext.createMarshaller().marshal(interchange, byteArrayOutputStream);

//${request.body} = new String(byteArrayOutputStream.toByteArray());

SmooksCaches.marshal(
                interchange,
                byteArrayOutputStream,
                Interchange.class,
                org.smooks.edifact.binding.service.ObjectFactory.class,
                org.smooks.edifact.binding.d96a.ObjectFactory.class
        );
        
${request.body} = SmooksCaches.translate("d96a", "INVOIC", byteArrayOutputStream, SmooksCaches.class.getClassLoader());     
