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