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 java.util.List;
051import org.apache.commons.codec.language.Soundex;
052import javax.enterprise.context.Dependent;
053import javax.inject.Inject;
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    @Inject
095    ContactControl contactControl;
096
097    @Inject
098    EntityInstanceControl entityInstanceControl;
099
100    @Inject
101    PartyControl partyControl;
102
103    @Inject
104    PartyPaymentMethodControl partyPaymentMethodControl;
105
106    @Inject
107    PaymentMethodControl paymentMethodControl;
108
109    @Inject
110    PaymentMethodTypePartyTypeControl paymentMethodTypePartyTypeControl;
111
112    @Inject
113    WorkflowControl workflowControl;
114
115    @Inject
116    PartyPaymentMethodLogic partyPaymentMethodLogic;
117
118    
119    /** Creates a new instance of CreatePartyPaymentMethodCommand */
120    public CreatePartyPaymentMethodCommand() {
121        super(COMMAND_SECURITY_DEFINITION, FORM_FIELD_DEFINITIONS, false);
122    }
123    
124    private void setupWorkflows(final PaymentMethodType paymentMethodType, final PartyType partyType,
125            final PartyPaymentMethodContactMechanism billingPartyPaymentMethodContactMechanism,
126            final PartyPaymentMethod partyPaymentMethod, final PartyPK createdBy) {
127        var paymentMethodTypePartyType = paymentMethodTypePartyTypeControl.getPaymentMethodTypePartyType(paymentMethodType, partyType);
128        
129        if(paymentMethodTypePartyType != null) {
130            var paymentMethodTypePartyTypeDetail = paymentMethodTypePartyType.getLastDetail();
131
132            if(billingPartyPaymentMethodContactMechanism != null) {
133                var contactMechanismWorkflow = paymentMethodTypePartyTypeDetail.getPartyContactMechanismWorkflow();
134
135                if(contactMechanismWorkflow != null) {
136                    var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(billingPartyPaymentMethodContactMechanism.getPrimaryKey());
137
138                    if(!workflowControl.isEntityInWorkflow(contactMechanismWorkflow, entityInstance)) {
139                        workflowControl.addEntityToWorkflow(contactMechanismWorkflow, entityInstance, null, null, createdBy);
140                    }
141                }
142            }
143
144            var partyPaymentMethodWorkflow = paymentMethodTypePartyTypeDetail.getPartyPaymentMethodWorkflow();
145            
146            if(partyPaymentMethodWorkflow != null) {
147                var entityInstance = entityInstanceControl.getEntityInstanceByBasePK(partyPaymentMethod.getPrimaryKey());
148                
149                workflowControl.addEntityToWorkflow(partyPaymentMethodWorkflow, entityInstance, null, null, createdBy);
150            }
151        }
152    }
153    
154    private PartyPaymentMethodContactMechanism setupPartyPaymentMethodContactMechanism(final ContactControl contactControl,
155            final PartyPaymentMethodControl partyPaymentMethodControl, final PartyContactMechanism partyContactMechanism,
156            final PartyPaymentMethod partyPaymentMethod, final PartyPK createdBy) {
157        var contactMechanismPurpose = contactControl.getContactMechanismPurposeByName(ContactMechanismPurposes.PHYSICAL_BILLING.name());
158        var partyContactMechanismPurpose = contactControl.getPartyContactMechanismPurpose(partyContactMechanism,
159                contactMechanismPurpose);
160        
161        if(partyContactMechanismPurpose == null) {
162            partyContactMechanismPurpose = contactControl.createPartyContactMechanismPurpose(partyContactMechanism,
163                    contactMechanismPurpose, false, 1, createdBy);
164        }
165        
166        return partyPaymentMethodControl.createPartyPaymentMethodContactMechanism(partyPaymentMethod, partyContactMechanismPurpose, createdBy);
167    }
168    
169    @Override
170    protected BaseResult execute() {
171        var result = PaymentResultFactory.getCreatePartyPaymentMethodResult();
172        var party = getParty();
173        var partyTypeName = party.getLastDetail().getPartyType().getPartyTypeName();
174
175        // If the caller is a CUSTOMER, then they're the Party. If they're not, the PartyName parameter is
176        // required, and we'll look them up.
177        if(!partyTypeName.equals(PartyTypes.CUSTOMER.name())) {
178            var partyName = form.getPartyName();
179
180            if(partyName == null) {
181                addExecutionError(ExecutionErrors.PartyNameRequired.name());
182            } else {
183                party = partyControl.getPartyByName(partyName);
184
185                if(party == null) {
186                    addExecutionError(ExecutionErrors.UnknownPartyName.name(), partyName);
187                }
188            }
189        }
190
191        if(!hasExecutionErrors()) {
192            var paymentMethodName = form.getPaymentMethodName();
193            var paymentMethod = paymentMethodControl.getPaymentMethodByName(paymentMethodName);
194
195            if(paymentMethod != null) {
196                partyPaymentMethodLogic.checkPartyPaymentMethod(session, getUserVisit(), this, party, paymentMethod, form);
197
198                if(!hasExecutionErrors()) {
199                    var paymentMethodType = paymentMethod.getLastDetail().getPaymentMethodType();
200                    var paymentMethodTypeName = paymentMethodType.getLastDetail().getPaymentMethodTypeName();
201
202                    if(paymentMethodTypeName.equals(PaymentMethodTypes.CREDIT_CARD.name())) {
203                        var soundex = new Soundex();
204                        var personalTitleId = form.getPersonalTitleId();
205                        var personalTitle = personalTitleId == null ? null : partyControl.convertPersonalTitleIdToEntity(personalTitleId, EntityPermission.READ_ONLY);
206                        var firstName = form.getFirstName();
207                        var middleName = form.getMiddleName();
208                        var lastName = form.getLastName();
209                        var nameSuffixId = form.getNameSuffixId();
210                        var nameSuffix = nameSuffixId == null ? null : partyControl.convertNameSuffixIdToEntity(nameSuffixId, EntityPermission.READ_ONLY);
211                        var name = form.getName();
212                        var number = form.getNumber();
213                        var securityCode = form.getSecurityCode();
214                        var strExpirationMonth = form.getExpirationMonth();
215                        var expirationMonth = strExpirationMonth != null? Integer.valueOf(strExpirationMonth): null;
216                        var strExpirationYear = form.getExpirationYear();
217                        var expirationYear = strExpirationYear != null? Integer.valueOf(strExpirationYear): null;
218                        var billingContactMechanismName = form.getBillingContactMechanismName();
219                        var billingContactMechanism = billingContactMechanismName == null ? null : contactControl.getContactMechanismByName(billingContactMechanismName);
220                        var billingPartyContactMechanism = billingContactMechanism == null? null: contactControl.getPartyContactMechanism(party, billingContactMechanism);
221                        var issuerName = form.getIssuerName();
222                        var issuerContactMechanismName = form.getIssuerContactMechanismName();
223                        var issuerContactMechanism = issuerContactMechanismName == null ? null : contactControl.getContactMechanismByName(issuerContactMechanismName);
224                        var issuerPartyContactMechanism = issuerContactMechanism == null? null: contactControl.getPartyContactMechanism(party, issuerContactMechanism);
225
226                        String firstNameSdx;
227                        try {
228                            firstNameSdx = firstName == null ? null : soundex.encode(firstName);
229                        } catch(IllegalArgumentException iae) {
230                            firstNameSdx = null;
231                        }
232
233                        String middleNameSdx;
234                        try {
235                            middleNameSdx = middleName == null ? null : soundex.encode(middleName);
236                        } catch(IllegalArgumentException iae) {
237                            middleNameSdx = null;
238                        }
239
240                        String lastNameSdx;
241                        try {
242                            lastNameSdx = lastName == null ? null : soundex.encode(lastName);
243                        } catch(IllegalArgumentException iae) {
244                            lastNameSdx = null;
245                        }
246
247                        var createdBy = getPartyPK();
248                        var description = form.getDescription();
249                        var deleteWhenUnused = Boolean.valueOf(form.getDeleteWhenUnused());
250                        var isDefault = Boolean.valueOf(form.getIsDefault());
251                        var sortOrder = Integer.valueOf(form.getSortOrder());
252
253                        var partyPaymentMethod = partyPaymentMethodControl.createPartyPaymentMethod(party, description,
254                                paymentMethod, deleteWhenUnused, isDefault, sortOrder, createdBy);
255
256                        partyPaymentMethodControl.createPartyPaymentMethodCreditCard(partyPaymentMethod, number, expirationMonth,
257                                expirationYear, personalTitle, firstName, firstNameSdx, middleName, middleNameSdx, lastName,
258                                lastNameSdx, nameSuffix, name, billingPartyContactMechanism, issuerName, issuerPartyContactMechanism,
259                                createdBy);
260
261                        partyPaymentMethodControl.createPartyPaymentMethodCreditCardSecurityCode(partyPaymentMethod, securityCode,
262                                createdBy);
263
264                        var billingPartyPaymentMethodContactMechanism = billingPartyContactMechanism == null ? null
265                                : setupPartyPaymentMethodContactMechanism(contactControl, partyPaymentMethodControl, billingPartyContactMechanism, partyPaymentMethod,
266                                createdBy);
267
268                        setupWorkflows(paymentMethodType, party.getLastDetail().getPartyType(),
269                                billingPartyPaymentMethodContactMechanism, partyPaymentMethod, createdBy);
270
271                        result.setEntityRef(partyPaymentMethod.getPrimaryKey().getEntityRef());
272                        result.setPartyPaymentMethodName(partyPaymentMethod.getLastDetail().getPartyPaymentMethodName());
273                    }
274                }
275            } else {
276                addExecutionError(ExecutionErrors.UnknownPaymentMethodName.name(), paymentMethodName);
277            }
278        }
279        
280        return result;
281    }
282    
283}