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