001// --------------------------------------------------------------------------------
002// Copyright 2002-2026 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.control.user.payment.server.command;
018
019import com.echothree.control.user.payment.common.form.CreatePartyPaymentMethodForm;
020import com.echothree.control.user.payment.common.result.PaymentResultFactory;
021import com.echothree.model.control.contact.common.ContactMechanismPurposes;
022import com.echothree.model.control.contact.server.control.ContactControl;
023import com.echothree.model.control.core.server.control.EntityInstanceControl;
024import com.echothree.model.control.party.common.PartyTypes;
025import com.echothree.model.control.party.server.control.PartyControl;
026import com.echothree.model.control.payment.common.PaymentMethodTypes;
027import com.echothree.model.control.payment.server.control.PartyPaymentMethodControl;
028import com.echothree.model.control.payment.server.control.PaymentMethodControl;
029import com.echothree.model.control.payment.server.control.PaymentMethodTypePartyTypeControl;
030import com.echothree.model.control.payment.server.logic.PartyPaymentMethodLogic;
031import com.echothree.model.control.security.common.SecurityRoleGroups;
032import com.echothree.model.control.security.common.SecurityRoles;
033import com.echothree.model.control.workflow.server.control.WorkflowControl;
034import com.echothree.model.data.contact.server.entity.PartyContactMechanism;
035import com.echothree.model.data.party.common.pk.PartyPK;
036import com.echothree.model.data.party.server.entity.PartyType;
037import com.echothree.model.data.payment.server.entity.PartyPaymentMethod;
038import com.echothree.model.data.payment.server.entity.PartyPaymentMethodContactMechanism;
039import com.echothree.model.data.payment.server.entity.PaymentMethodType;
040import com.echothree.model.data.user.common.pk.UserVisitPK;
041import com.echothree.util.common.command.BaseResult;
042import com.echothree.util.common.message.ExecutionErrors;
043import com.echothree.util.common.validation.FieldDefinition;
044import com.echothree.util.common.validation.FieldType;
045import com.echothree.util.server.control.BaseSimpleCommand;
046import com.echothree.util.server.control.CommandSecurityDefinition;
047import com.echothree.util.server.control.PartyTypeDefinition;
048import com.echothree.util.server.control.SecurityRoleDefinition;
049import com.echothree.util.server.persistence.EntityPermission;
050import com.echothree.util.server.persistence.Session;
051import java.util.List;
052import org.apache.commons.codec.language.Soundex;
053import javax.enterprise.context.Dependent;
054
055@Dependent
056public class CreatePartyPaymentMethodCommand
057        extends BaseSimpleCommand<CreatePartyPaymentMethodForm> {
058    
059    private final static CommandSecurityDefinition COMMAND_SECURITY_DEFINITION;
060    private final static List<FieldDefinition> FORM_FIELD_DEFINITIONS;
061    
062    static {
063        COMMAND_SECURITY_DEFINITION = new CommandSecurityDefinition(List.of(
064                new PartyTypeDefinition(PartyTypes.UTILITY.name(), null),
065                new PartyTypeDefinition(PartyTypes.CUSTOMER.name(), null),
066                new PartyTypeDefinition(PartyTypes.EMPLOYEE.name(), List.of(
067                        new SecurityRoleDefinition(SecurityRoleGroups.PartyPaymentMethod.name(), SecurityRoles.Create.name())
068                        ))
069                ));
070
071        FORM_FIELD_DEFINITIONS = List.of(
072                new FieldDefinition("PartyName", FieldType.ENTITY_NAME, false, null, null),
073                new FieldDefinition("Description", FieldType.STRING, false, 1L, 132L),
074                new FieldDefinition("PaymentMethodName", FieldType.ENTITY_NAME, true, null, null),
075                new FieldDefinition("DeleteWhenUnused", FieldType.BOOLEAN, true, null, null),
076                new FieldDefinition("IsDefault", FieldType.BOOLEAN, true, null, null),
077                new FieldDefinition("SortOrder", FieldType.SIGNED_INTEGER, true, null, null),
078                new FieldDefinition("Number", FieldType.STRING, false, 1L, 20L), // RegExp Validated
079                new FieldDefinition("SecurityCode", FieldType.STRING, false, 1L, 10L), // RegExp Validated
080                new FieldDefinition("ExpirationMonth", FieldType.CREDIT_CARD_MONTH, false, null, null),
081                new FieldDefinition("ExpirationYear", FieldType.CREDIT_CARD_YEAR, false, null, null),
082                new FieldDefinition("PersonalTitleId", FieldType.ID, false, null, null),
083                new FieldDefinition("FirstName", FieldType.STRING, false, 1L, 20L),
084                new FieldDefinition("MiddleName", FieldType.STRING, false, 1L, 20L),
085                new FieldDefinition("LastName", FieldType.STRING, false, 1L, 20L),
086                new FieldDefinition("NameSuffixId", FieldType.ID, false, null, null),
087                new FieldDefinition("Name", FieldType.STRING, false, 1L, 60L),
088                new FieldDefinition("BillingContactMechanismName", FieldType.ENTITY_NAME, false, null, null),
089                new FieldDefinition("IssuerName", FieldType.STRING, false, 1L, 60L),
090                new FieldDefinition("IssuerContactMechanismName", FieldType.ENTITY_NAME, false, null, null)
091                );
092    }
093    
094    /** Creates a new instance of CreatePartyPaymentMethodCommand */
095    public CreatePartyPaymentMethodCommand() {
096        super(COMMAND_SECURITY_DEFINITION, FORM_FIELD_DEFINITIONS, false);
097    }
098    
099    private void setupWorkflows(final PaymentMethodType paymentMethodType, final PartyType partyType,
100            final PartyPaymentMethodContactMechanism billingPartyPaymentMethodContactMechanism,
101            final PartyPaymentMethod partyPaymentMethod, final PartyPK createdBy) {
102        var paymentMethodTypePartyTypeControl = Session.getModelController(PaymentMethodTypePartyTypeControl.class);
103        var workflowControl = Session.getModelController(WorkflowControl.class);
104        var paymentMethodTypePartyType = paymentMethodTypePartyTypeControl.getPaymentMethodTypePartyType(paymentMethodType, partyType);
105        
106        if(paymentMethodTypePartyType != null) {
107            var entityInstanceControl = Session.getModelController(EntityInstanceControl.class);
108            var paymentMethodTypePartyTypeDetail = paymentMethodTypePartyType.getLastDetail();
109
110            if(billingPartyPaymentMethodContactMechanism != null) {
111                var contactMechanismWorkflow = paymentMethodTypePartyTypeDetail.getPartyContactMechanismWorkflow();
112
113                if(contactMechanismWorkflow != null) {
114                    var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(billingPartyPaymentMethodContactMechanism.getPrimaryKey());
115
116                    if(!workflowControl.isEntityInWorkflow(contactMechanismWorkflow, entityInstance)) {
117                        workflowControl.addEntityToWorkflow(contactMechanismWorkflow, entityInstance, null, null, createdBy);
118                    }
119                }
120            }
121
122            var partyPaymentMethodWorkflow = paymentMethodTypePartyTypeDetail.getPartyPaymentMethodWorkflow();
123            
124            if(partyPaymentMethodWorkflow != null) {
125                var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(partyPaymentMethod.getPrimaryKey());
126                
127                workflowControl.addEntityToWorkflow(partyPaymentMethodWorkflow, entityInstance, null, null, createdBy);
128            }
129        }
130    }
131    
132    private PartyPaymentMethodContactMechanism setupPartyPaymentMethodContactMechanism(final ContactControl contactControl,
133            final PartyPaymentMethodControl partyPaymentMethodControl, final PartyContactMechanism partyContactMechanism,
134            final PartyPaymentMethod partyPaymentMethod, final PartyPK createdBy) {
135        var contactMechanismPurpose = contactControl.getContactMechanismPurposeByName(ContactMechanismPurposes.PHYSICAL_BILLING.name());
136        var partyContactMechanismPurpose = contactControl.getPartyContactMechanismPurpose(partyContactMechanism,
137                contactMechanismPurpose);
138        
139        if(partyContactMechanismPurpose == null) {
140            partyContactMechanismPurpose = contactControl.createPartyContactMechanismPurpose(partyContactMechanism,
141                    contactMechanismPurpose, false, 1, createdBy);
142        }
143        
144        return partyPaymentMethodControl.createPartyPaymentMethodContactMechanism(partyPaymentMethod, partyContactMechanismPurpose, createdBy);
145    }
146    
147    @Override
148    protected BaseResult execute() {
149        var partyControl = Session.getModelController(PartyControl.class);
150        var result = PaymentResultFactory.getCreatePartyPaymentMethodResult();
151        var party = getParty();
152        var partyTypeName = party.getLastDetail().getPartyType().getPartyTypeName();
153
154        // If the caller is a CUSTOMER, then they're the Party. If they're not, the PartyName parameter is
155        // required, and we'll look them up.
156        if(!partyTypeName.equals(PartyTypes.CUSTOMER.name())) {
157            var partyName = form.getPartyName();
158
159            if(partyName == null) {
160                addExecutionError(ExecutionErrors.PartyNameRequired.name());
161            } else {
162                party = partyControl.getPartyByName(partyName);
163
164                if(party == null) {
165                    addExecutionError(ExecutionErrors.UnknownPartyName.name(), partyName);
166                }
167            }
168        }
169
170        if(!hasExecutionErrors()) {
171            var paymentMethodControl = Session.getModelController(PaymentMethodControl.class);
172            var paymentMethodName = form.getPaymentMethodName();
173            var paymentMethod = paymentMethodControl.getPaymentMethodByName(paymentMethodName);
174
175            if(paymentMethod != null) {
176                PartyPaymentMethodLogic.getInstance().checkPartyPaymentMethod(session, getUserVisit(), this, party, paymentMethod, form);
177
178                if(!hasExecutionErrors()) {
179                    var paymentMethodType = paymentMethod.getLastDetail().getPaymentMethodType();
180                    var paymentMethodTypeName = paymentMethodType.getLastDetail().getPaymentMethodTypeName();
181
182                    if(paymentMethodTypeName.equals(PaymentMethodTypes.CREDIT_CARD.name())) {
183                        var partyPaymentMethodControl = Session.getModelController(PartyPaymentMethodControl.class);
184                        var contactControl = Session.getModelController(ContactControl.class);
185                        var soundex = new Soundex();
186                        var personalTitleId = form.getPersonalTitleId();
187                        var personalTitle = personalTitleId == null ? null : partyControl.convertPersonalTitleIdToEntity(personalTitleId, EntityPermission.READ_ONLY);
188                        var firstName = form.getFirstName();
189                        var middleName = form.getMiddleName();
190                        var lastName = form.getLastName();
191                        var nameSuffixId = form.getNameSuffixId();
192                        var nameSuffix = nameSuffixId == null ? null : partyControl.convertNameSuffixIdToEntity(nameSuffixId, EntityPermission.READ_ONLY);
193                        var name = form.getName();
194                        var number = form.getNumber();
195                        var securityCode = form.getSecurityCode();
196                        var strExpirationMonth = form.getExpirationMonth();
197                        var expirationMonth = strExpirationMonth != null? Integer.valueOf(strExpirationMonth): null;
198                        var strExpirationYear = form.getExpirationYear();
199                        var expirationYear = strExpirationYear != null? Integer.valueOf(strExpirationYear): null;
200                        var billingContactMechanismName = form.getBillingContactMechanismName();
201                        var billingContactMechanism = billingContactMechanismName == null ? null : contactControl.getContactMechanismByName(billingContactMechanismName);
202                        var billingPartyContactMechanism = billingContactMechanism == null? null: contactControl.getPartyContactMechanism(party, billingContactMechanism);
203                        var issuerName = form.getIssuerName();
204                        var issuerContactMechanismName = form.getIssuerContactMechanismName();
205                        var issuerContactMechanism = issuerContactMechanismName == null ? null : contactControl.getContactMechanismByName(issuerContactMechanismName);
206                        var issuerPartyContactMechanism = issuerContactMechanism == null? null: contactControl.getPartyContactMechanism(party, issuerContactMechanism);
207
208                        String firstNameSdx;
209                        try {
210                            firstNameSdx = firstName == null ? null : soundex.encode(firstName);
211                        } catch(IllegalArgumentException iae) {
212                            firstNameSdx = null;
213                        }
214
215                        String middleNameSdx;
216                        try {
217                            middleNameSdx = middleName == null ? null : soundex.encode(middleName);
218                        } catch(IllegalArgumentException iae) {
219                            middleNameSdx = null;
220                        }
221
222                        String lastNameSdx;
223                        try {
224                            lastNameSdx = lastName == null ? null : soundex.encode(lastName);
225                        } catch(IllegalArgumentException iae) {
226                            lastNameSdx = null;
227                        }
228
229                        var createdBy = getPartyPK();
230                        var description = form.getDescription();
231                        var deleteWhenUnused = Boolean.valueOf(form.getDeleteWhenUnused());
232                        var isDefault = Boolean.valueOf(form.getIsDefault());
233                        var sortOrder = Integer.valueOf(form.getSortOrder());
234
235                        var partyPaymentMethod = partyPaymentMethodControl.createPartyPaymentMethod(party, description,
236                                paymentMethod, deleteWhenUnused, isDefault, sortOrder, createdBy);
237
238                        partyPaymentMethodControl.createPartyPaymentMethodCreditCard(partyPaymentMethod, number, expirationMonth,
239                                expirationYear, personalTitle, firstName, firstNameSdx, middleName, middleNameSdx, lastName,
240                                lastNameSdx, nameSuffix, name, billingPartyContactMechanism, issuerName, issuerPartyContactMechanism,
241                                createdBy);
242
243                        partyPaymentMethodControl.createPartyPaymentMethodCreditCardSecurityCode(partyPaymentMethod, securityCode,
244                                createdBy);
245
246                        var billingPartyPaymentMethodContactMechanism = billingPartyContactMechanism == null ? null
247                                : setupPartyPaymentMethodContactMechanism(contactControl, partyPaymentMethodControl, billingPartyContactMechanism, partyPaymentMethod,
248                                createdBy);
249
250                        setupWorkflows(paymentMethodType, party.getLastDetail().getPartyType(),
251                                billingPartyPaymentMethodContactMechanism, partyPaymentMethod, createdBy);
252
253                        result.setEntityRef(partyPaymentMethod.getPrimaryKey().getEntityRef());
254                        result.setPartyPaymentMethodName(partyPaymentMethod.getLastDetail().getPartyPaymentMethodName());
255                    }
256                }
257            } else {
258                addExecutionError(ExecutionErrors.UnknownPaymentMethodName.name(), paymentMethodName);
259            }
260        }
261        
262        return result;
263    }
264    
265}