001// -------------------------------------------------------------------------------- 002// Copyright 2002-2025 Echo Three, LLC 003// 004// Licensed under the Apache License, Version 2.0 (the "License"); 005// you may not use this file except in compliance with the License. 006// You may obtain a copy of the License at 007// 008// http://www.apache.org/licenses/LICENSE-2.0 009// 010// Unless required by applicable law or agreed to in writing, software 011// distributed under the License is distributed on an "AS IS" BASIS, 012// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013// See the License for the specific language governing permissions and 014// limitations under the License. 015// -------------------------------------------------------------------------------- 016 017package com.echothree.model.control.invoice.server.logic; 018 019import com.echothree.model.control.accounting.common.AccountingConstants; 020import com.echothree.model.control.accounting.server.logic.GlAccountLogic; 021import com.echothree.model.control.core.server.control.EntityInstanceControl; 022import com.echothree.model.control.invoice.common.InvoiceTypes; 023import com.echothree.model.control.invoice.common.choice.PurchaseInvoiceStatusChoicesBean; 024import com.echothree.model.control.invoice.common.workflow.PurchaseInvoiceStatusConstants; 025import com.echothree.model.control.invoice.server.control.InvoiceControl; 026import com.echothree.model.control.vendor.server.control.VendorControl; 027import com.echothree.model.control.workflow.server.control.WorkflowControl; 028import com.echothree.model.data.accounting.server.entity.Currency; 029import com.echothree.model.data.accounting.server.entity.GlAccount; 030import com.echothree.model.data.contact.server.entity.PartyContactMechanism; 031import com.echothree.model.data.invoice.server.entity.Invoice; 032import com.echothree.model.data.invoice.server.entity.InvoiceLine; 033import com.echothree.model.data.invoice.server.entity.InvoiceLineType; 034import com.echothree.model.data.party.common.pk.PartyPK; 035import com.echothree.model.data.party.server.entity.Language; 036import com.echothree.model.data.party.server.entity.Party; 037import com.echothree.model.data.shipment.server.entity.FreeOnBoard; 038import com.echothree.model.data.term.server.entity.Term; 039import com.echothree.model.data.vendor.server.entity.Vendor; 040import com.echothree.util.common.message.ExecutionErrors; 041import com.echothree.util.common.persistence.BasePK; 042import com.echothree.util.server.message.ExecutionErrorAccumulator; 043import com.echothree.util.server.persistence.Session; 044import javax.enterprise.context.ApplicationScoped; 045import javax.enterprise.inject.spi.CDI; 046 047@ApplicationScoped 048public class PurchaseInvoiceLogic { 049 050 protected PurchaseInvoiceLogic() { 051 super(); 052 } 053 054 public static PurchaseInvoiceLogic getInstance() { 055 return CDI.current().select(PurchaseInvoiceLogic.class).get(); 056 } 057 058 public Invoice getInvoiceByName(String invoiceName) { 059 var invoiceControl = Session.getModelController(InvoiceControl.class); 060 061 return invoiceControl.getInvoiceByNameUsingNames(InvoiceTypes.PURCHASE_INVOICE.name(), invoiceName); 062 } 063 064 protected void validateReference(final ExecutionErrorAccumulator eea, final Party billFrom, final String reference, final Vendor vendor) { 065 if(vendor.getRequireReference() && reference == null) { 066 eea.addExecutionError(ExecutionErrors.PurchaseInvoiceReferenceRequired.name()); 067 } else if(reference != null) { 068 var invoiceControl = Session.getModelController(InvoiceControl.class); 069 070 if(!vendor.getAllowReferenceDuplicates() && invoiceControl.countInvoicesByInvoiceFromAndReference(billFrom, reference) != 0) { 071 eea.addExecutionError(ExecutionErrors.PurchaseInvoiceDuplicateReference.name()); 072 } else { 073 var referenceValidationPattern = vendor.getReferenceValidationPattern(); 074 075 if(referenceValidationPattern != null && !reference.matches(referenceValidationPattern)) { 076 eea.addExecutionError(ExecutionErrors.InvalidPurchaseInvoiceReference.name()); 077 } 078 } 079 } 080 } 081 082 protected GlAccount getApGlAccount(final ExecutionErrorAccumulator eea, final Vendor vendor) { 083 var vendorApGlAccount = vendor.getApGlAccount(); 084 var vendorTypeDefaultApGlAccount = vendor.getVendorType().getLastDetail().getDefaultApGlAccount(); 085 var glAccounts = new GlAccount[]{vendorApGlAccount, vendorTypeDefaultApGlAccount}; 086 087 return GlAccountLogic.getInstance().getDefaultGlAccountByCategory(eea, new GlAccount[]{ 088 vendor.getApGlAccount(), 089 vendor.getVendorType().getLastDetail().getDefaultApGlAccount() 090 }, AccountingConstants.GlAccountCategory_ACCOUNTS_PAYABLE, ExecutionErrors.UnknownDefaultApGlAccount.name()); 091 } 092 093 public Invoice createInvoice(final Session session, final ExecutionErrorAccumulator eea, final Party billFrom, 094 final PartyContactMechanism billFromPartyContactMechanism, final Party billTo, final PartyContactMechanism billToPartyContactMechanism, 095 final Currency currency, final Term term, final FreeOnBoard freeOnBoard, final String reference, 096 final String description, final Long invoicedTime, final Long dueTime, 097 final Long paidTime, final String workflowEntranceName, final BasePK createdBy) { 098 Invoice invoice = null; 099 var vendorControl = Session.getModelController(VendorControl.class); 100 var vendor = vendorControl.getVendor(billFrom); 101 var glAccount = getApGlAccount(eea, vendor); 102 103 validateReference(eea, billFrom, reference, vendor); 104 105 if(eea == null || !eea.hasExecutionErrors()) { 106 invoice = InvoiceLogic.getInstance().createInvoice(session, eea, InvoiceTypes.PURCHASE_INVOICE.name(), billFrom, 107 billFromPartyContactMechanism, billTo, billToPartyContactMechanism, currency, glAccount, term, 108 freeOnBoard, reference, description, invoicedTime, dueTime, paidTime, createdBy); 109 110 if(!eea.hasExecutionErrors() && workflowEntranceName != null) { 111 var entityInstanceControl = Session.getModelController(EntityInstanceControl.class); 112 var workflowControl = Session.getModelController(WorkflowControl.class); 113 var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(invoice.getPrimaryKey()); 114 115 workflowControl.addEntityToWorkflowUsingNames(null, PurchaseInvoiceStatusConstants.Workflow_PURCHASE_INVOICE_STATUS, workflowEntranceName, 116 entityInstance, null, null, createdBy); 117 } 118 } 119 120 return invoice; 121 } 122 123 public InvoiceLine createInvoiceLine(final ExecutionErrorAccumulator eea, final Invoice invoice, final Integer invoiceLineSequence, final InvoiceLine parentInvoiceLine, 124 final Long amount, final InvoiceLineType invoiceLineType, final GlAccount glAccount, final String description, final BasePK createdBy) { 125 var entityInstanceControl = Session.getModelController(EntityInstanceControl.class); 126 var workflowControl = Session.getModelController(WorkflowControl.class); 127 InvoiceLine invoiceLine = null; 128 var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(invoice.getPrimaryKey()); 129 var workflowEntityStatus = workflowControl.getWorkflowEntityStatusByEntityInstanceUsingNames(PurchaseInvoiceStatusConstants.Workflow_PURCHASE_INVOICE_STATUS, entityInstance); 130 var workflowStepName = workflowEntityStatus.getWorkflowStep().getLastDetail().getWorkflowStepName(); 131 132 if(workflowStepName.equals(PurchaseInvoiceStatusConstants.WorkflowStep_ENTRY)) { 133 invoiceLine = InvoiceLogic.getInstance().createInvoiceLine(eea, invoice, invoiceLineSequence, parentInvoiceLine, amount, invoiceLineType, glAccount, description, createdBy); 134 } else { 135 eea.addExecutionError(ExecutionErrors.InvalidPurchaseInvoiceStatus.name(), invoice.getLastDetail().getInvoiceName(), workflowStepName); 136 } 137 138 return invoiceLine; 139 } 140 141 public PurchaseInvoiceStatusChoicesBean getPurchaseInvoiceStatusChoices(final String defaultInvoiceStatusChoice, final Language language, final boolean allowNullChoice, 142 final Invoice invoice, final PartyPK partyPK) { 143 var workflowControl = Session.getModelController(WorkflowControl.class); 144 var purchaseInvoiceStatusChoicesBean = new PurchaseInvoiceStatusChoicesBean(); 145 146 if(invoice == null) { 147 workflowControl.getWorkflowEntranceChoices(purchaseInvoiceStatusChoicesBean, defaultInvoiceStatusChoice, language, allowNullChoice, 148 workflowControl.getWorkflowByName(PurchaseInvoiceStatusConstants.Workflow_PURCHASE_INVOICE_STATUS), partyPK); 149 } else { 150 var entityInstanceControl = Session.getModelController(EntityInstanceControl.class); 151 var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(invoice.getPrimaryKey()); 152 var workflowEntityStatus = workflowControl.getWorkflowEntityStatusByEntityInstanceUsingNames(PurchaseInvoiceStatusConstants.Workflow_PURCHASE_INVOICE_STATUS, entityInstance); 153 154 workflowControl.getWorkflowDestinationChoices(purchaseInvoiceStatusChoicesBean, defaultInvoiceStatusChoice, language, allowNullChoice, workflowEntityStatus.getWorkflowStep(), partyPK); 155 } 156 157 return purchaseInvoiceStatusChoicesBean; 158 } 159 160 public void setPurchaseInvoiceStatus(final ExecutionErrorAccumulator eea, final Invoice invoice, final String invoiceStatusChoice, final PartyPK modifiedBy) { 161 var entityInstanceControl = Session.getModelController(EntityInstanceControl.class); 162 var workflowControl = Session.getModelController(WorkflowControl.class); 163 var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(invoice.getPrimaryKey()); 164 var workflowEntityStatus = workflowControl.getWorkflowEntityStatusByEntityInstanceForUpdateUsingNames(PurchaseInvoiceStatusConstants.Workflow_PURCHASE_INVOICE_STATUS, 165 entityInstance); 166 var workflowDestination = invoiceStatusChoice == null? null: workflowControl.getWorkflowDestinationByName(workflowEntityStatus.getWorkflowStep(), invoiceStatusChoice); 167 168 if(workflowDestination != null || invoiceStatusChoice == null) { 169 workflowControl.transitionEntityInWorkflow(eea, workflowEntityStatus, workflowDestination, null, modifiedBy); 170 } else { 171 eea.addExecutionError(ExecutionErrors.UnknownPurchaseInvoiceStatusChoice.name(), invoiceStatusChoice); 172 } 173 } 174 175}