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.edit.PartyPaymentMethodEdit;
020import com.echothree.control.user.payment.common.edit.PaymentEditFactory;
021import com.echothree.control.user.payment.common.form.EditPartyPaymentMethodForm;
022import com.echothree.control.user.payment.common.result.EditPartyPaymentMethodResult;
023import com.echothree.control.user.payment.common.result.PaymentResultFactory;
024import com.echothree.control.user.payment.common.spec.PartyPaymentMethodSpec;
025import com.echothree.model.control.contact.server.control.ContactControl;
026import com.echothree.model.control.party.common.PartyTypes;
027import com.echothree.model.control.party.server.control.PartyControl;
028import com.echothree.model.control.payment.common.PaymentMethodTypes;
029import com.echothree.model.control.payment.server.control.PartyPaymentMethodControl;
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.data.party.server.entity.Party;
034import com.echothree.model.data.payment.server.entity.PartyPaymentMethod;
035import com.echothree.model.data.user.common.pk.UserVisitPK;
036import com.echothree.util.common.command.EditMode;
037import com.echothree.util.common.message.ExecutionErrors;
038import com.echothree.util.common.validation.FieldDefinition;
039import com.echothree.util.common.validation.FieldType;
040import com.echothree.util.server.control.BaseAbstractEditCommand;
041import com.echothree.util.server.control.CommandSecurityDefinition;
042import com.echothree.util.server.control.PartyTypeDefinition;
043import com.echothree.util.server.control.SecurityRoleDefinition;
044import com.echothree.util.server.persistence.EntityPermission;
045import java.util.List;
046import org.apache.commons.codec.language.Soundex;
047import javax.enterprise.context.Dependent;
048import javax.inject.Inject;
049
050@Dependent
051public class EditPartyPaymentMethodCommand
052        extends BaseAbstractEditCommand<PartyPaymentMethodSpec, PartyPaymentMethodEdit, EditPartyPaymentMethodResult, PartyPaymentMethod, PartyPaymentMethod> {
053    
054    private final static CommandSecurityDefinition COMMAND_SECURITY_DEFINITION;
055    private final static List<FieldDefinition> SPEC_FIELD_DEFINITIONS;
056    private final static List<FieldDefinition> EDIT_FIELD_DEFINITIONS;
057    
058    static {
059        COMMAND_SECURITY_DEFINITION = new CommandSecurityDefinition(List.of(
060                new PartyTypeDefinition(PartyTypes.UTILITY.name(), null),
061                new PartyTypeDefinition(PartyTypes.CUSTOMER.name(), null),
062                new PartyTypeDefinition(PartyTypes.EMPLOYEE.name(), List.of(
063                        new SecurityRoleDefinition(SecurityRoleGroups.PartyPaymentMethod.name(), SecurityRoles.Edit.name())
064                ))
065        ));
066
067        SPEC_FIELD_DEFINITIONS = List.of(
068                new FieldDefinition("PartyPaymentMethodName", FieldType.ENTITY_NAME, true, null, null)
069        );
070        
071        EDIT_FIELD_DEFINITIONS = List.of(
072                new FieldDefinition("Description", FieldType.STRING, false, 1L, 132L),
073                new FieldDefinition("DeleteWhenUnused", FieldType.BOOLEAN, true, null, null),
074                new FieldDefinition("IsDefault", FieldType.BOOLEAN, true, null, null),
075                new FieldDefinition("SortOrder", FieldType.SIGNED_INTEGER, true, null, null),
076                new FieldDefinition("Number", FieldType.STRING, false, 1L, 20L), // RegExp Validated
077                new FieldDefinition("SecurityCode", FieldType.STRING, false, 1L, 10L), // RegExp Validated
078                new FieldDefinition("ExpirationMonth", FieldType.CREDIT_CARD_MONTH, false, null, null),
079                new FieldDefinition("ExpirationYear", FieldType.CREDIT_CARD_YEAR, false, null, null),
080                new FieldDefinition("PersonalTitleId", FieldType.ID, false, null, null),
081                new FieldDefinition("FirstName", FieldType.STRING, false, 1L, 20L),
082                new FieldDefinition("MiddleName", FieldType.STRING, false, 1L, 20L),
083                new FieldDefinition("LastName", FieldType.STRING, false, 1L, 20L),
084                new FieldDefinition("NameSuffixId", FieldType.ID, false, null, null),
085                new FieldDefinition("Name", FieldType.STRING, false, 1L, 60L),
086                new FieldDefinition("BillingContactMechanismName", FieldType.ENTITY_NAME, false, null, null),
087                new FieldDefinition("IssuerName", FieldType.STRING, false, 1L, 60L),
088                new FieldDefinition("IssuerContactMechanismName", FieldType.ENTITY_NAME, false, null, null)
089        );
090    }
091
092    @Inject
093    ContactControl contactControl;
094
095    @Inject
096    PartyControl partyControl;
097
098    @Inject
099    PartyPaymentMethodControl partyPaymentMethodControl;
100
101    @Inject
102    PartyPaymentMethodLogic partyPaymentMethodLogic;
103
104    
105    /** Creates a new instance of EditPartyPaymentMethodCommand */
106    public EditPartyPaymentMethodCommand() {
107        super(COMMAND_SECURITY_DEFINITION, SPEC_FIELD_DEFINITIONS, EDIT_FIELD_DEFINITIONS);
108    }
109    
110    @Override
111    public EditPartyPaymentMethodResult getResult() {
112        return PaymentResultFactory.getEditPartyPaymentMethodResult();
113    }
114
115    @Override
116    public PartyPaymentMethodEdit getEdit() {
117        return PaymentEditFactory.getPartyPaymentMethodEdit();
118    }
119
120    @Override
121    public PartyPaymentMethod getEntity(EditPartyPaymentMethodResult result) {
122        PartyPaymentMethod partyPaymentMethod;
123        var partyPaymentMethodName = spec.getPartyPaymentMethodName();
124
125        if(editMode.equals(EditMode.LOCK) || editMode.equals(EditMode.ABANDON)) {
126            partyPaymentMethod = partyPaymentMethodControl.getPartyPaymentMethodByName(partyPaymentMethodName);
127        } else { // EditMode.UPDATE
128            partyPaymentMethod = partyPaymentMethodControl.getPartyPaymentMethodByNameForUpdate(partyPaymentMethodName);
129        }
130
131        if(partyPaymentMethod != null) {
132            var party = getParty();
133            var partyTypeName = party.getLastDetail().getPartyType().getPartyTypeName();
134
135            // If the executing Party is a CUSTOMER, and the PartyPaymentMethod isn't for the executing Party,
136            // return a UnknownPartyPaymentMethodName error.
137            if(partyTypeName.equals(PartyTypes.CUSTOMER.name())) {
138                if(!partyPaymentMethod.getLastDetail().getParty().equals(party)) {
139                    partyPaymentMethod = null;
140                }
141            }
142        }
143
144        if(partyPaymentMethod == null) {
145            addExecutionError(ExecutionErrors.UnknownPartyPaymentMethodName.name(), partyPaymentMethodName);
146        } else {
147            result.setPartyPaymentMethod(partyPaymentMethodControl.getPartyPaymentMethodTransfer(getUserVisit(), partyPaymentMethod));
148        }
149
150        return partyPaymentMethod;
151    }
152
153    @Override
154    public PartyPaymentMethod getLockEntity(PartyPaymentMethod partyPaymentMethod) {
155        return partyPaymentMethod;
156    }
157
158    @Override
159    public void fillInResult(EditPartyPaymentMethodResult result, PartyPaymentMethod partyPaymentMethod) {
160        result.setPartyPaymentMethod(partyPaymentMethodControl.getPartyPaymentMethodTransfer(getUserVisit(), partyPaymentMethod));
161    }
162
163    @Override
164    public void doLock(PartyPaymentMethodEdit edit, PartyPaymentMethod partyPaymentMethod) {
165        var partyPaymentMethodDetail = partyPaymentMethod.getLastDetail();
166        var paymentMethodTypeName = partyPaymentMethodDetail.getPaymentMethod().getLastDetail().getPaymentMethodType().getLastDetail().getPaymentMethodTypeName();
167
168        edit.setDescription(partyPaymentMethodDetail.getDescription());
169        edit.setDeleteWhenUnused(partyPaymentMethodDetail.getDeleteWhenUnused().toString());
170        edit.setIsDefault(partyPaymentMethodDetail.getIsDefault().toString());
171        edit.setSortOrder(partyPaymentMethodDetail.getSortOrder().toString());
172
173        if(paymentMethodTypeName.equals(PaymentMethodTypes.CREDIT_CARD.name())) {
174            var partyPaymentMethodCreditCard = partyPaymentMethodControl.getPartyPaymentMethodCreditCard(partyPaymentMethod);
175            var partyPaymentMethodCreditCardSecurityCode = partyPaymentMethodControl.getPartyPaymentMethodCreditCardSecurityCode(partyPaymentMethod);
176            var includeCreditCardNumber = securityRoleLogic.hasSecurityRoleUsingNames(null, getParty(),
177                    SecurityRoleGroups.PartyPaymentMethod.name(), SecurityRoles.CreditCard.name());
178
179            if(partyPaymentMethodCreditCard != null) {
180                var personalTitle = partyPaymentMethodCreditCard.getPersonalTitle();
181                var nameSuffix = partyPaymentMethodCreditCard.getNameSuffix();
182                var expirationMonth = partyPaymentMethodCreditCard.getExpirationMonth();
183                var expirationYear = partyPaymentMethodCreditCard.getExpirationYear();
184                var billingPartyContactMechanism = partyPaymentMethodCreditCard.getBillingPartyContactMechanism();
185                var issuerPartyContactMechanism = partyPaymentMethodCreditCard.getIssuerPartyContactMechanism();
186
187                edit.setPersonalTitleId(personalTitle == null? null: personalTitle.getPrimaryKey().getEntityId().toString());
188                edit.setFirstName(partyPaymentMethodCreditCard.getFirstName());
189                edit.setMiddleName(partyPaymentMethodCreditCard.getMiddleName());
190                edit.setLastName(partyPaymentMethodCreditCard.getLastName());
191                edit.setNameSuffixId(nameSuffix == null? null: nameSuffix.getPrimaryKey().getEntityId().toString());
192                edit.setName(partyPaymentMethodCreditCard.getName());
193                if(includeCreditCardNumber) {
194                    edit.setNumber(partyPaymentMethodControl.decodePartyPaymentMethodCreditCardNumber(partyPaymentMethodCreditCard));
195                }
196                edit.setExpirationMonth(expirationMonth == null? null: expirationMonth.toString());
197                edit.setExpirationYear(expirationYear == null? null: expirationYear.toString());
198                edit.setBillingContactMechanismName(billingPartyContactMechanism == null? null: billingPartyContactMechanism.getLastDetail().getContactMechanism().getLastDetail().getContactMechanismName());
199                edit.setIssuerName(partyPaymentMethodCreditCard.getIssuerName());
200                edit.setIssuerContactMechanismName(issuerPartyContactMechanism == null? null: issuerPartyContactMechanism.getLastDetail().getContactMechanism().getLastDetail().getContactMechanismName());
201            }
202
203            if(partyPaymentMethodCreditCardSecurityCode != null) {
204                if(includeCreditCardNumber) {
205                    edit.setSecurityCode(partyPaymentMethodControl.decodePartyPaymentMethodCreditCardSecurityCodeSecurityCode(partyPaymentMethodCreditCardSecurityCode));
206                }
207            }
208        }
209    }
210
211    private Party getPartyFromPartyPaymentMethod(PartyPaymentMethod partyPaymentMethod) {
212        return partyPaymentMethod.getLastDetail().getParty();
213    }
214
215    @Override
216    public void canUpdate(PartyPaymentMethod partyPaymentMethod) {
217        partyPaymentMethodLogic.checkPartyPaymentMethod(session, getUserVisit(), this, getPartyFromPartyPaymentMethod(partyPaymentMethod),
218                partyPaymentMethod.getLastDetail().getPaymentMethod(), edit);
219    }
220
221    @Override
222    public void doUpdate(PartyPaymentMethod partyPaymentMethod) {
223        var executingPartyPK = getPartyPK();
224        var partyPaymentMethodDetailValue = partyPaymentMethodControl.getPartyPaymentMethodDetailValueForUpdate(partyPaymentMethod);
225        var paymentMethodTypeName = partyPaymentMethod.getLastDetail().getPaymentMethod().getLastDetail().getPaymentMethodType().getLastDetail().getPaymentMethodTypeName();
226
227        partyPaymentMethodDetailValue.setDescription(edit.getDescription());
228        partyPaymentMethodDetailValue.setDeleteWhenUnused(Boolean.valueOf(edit.getDeleteWhenUnused()));
229        partyPaymentMethodDetailValue.setIsDefault(Boolean.valueOf(edit.getIsDefault()));
230        partyPaymentMethodDetailValue.setSortOrder(Integer.valueOf(edit.getSortOrder()));
231
232        partyPaymentMethodControl.updatePartyPaymentMethodFromValue(partyPaymentMethodDetailValue, executingPartyPK);
233
234        if(paymentMethodTypeName.equals(PaymentMethodTypes.CREDIT_CARD.name())) {
235            var party = getPartyFromPartyPaymentMethod(partyPaymentMethod);
236            var soundex = new Soundex();
237            var personalTitleId = edit.getPersonalTitleId();
238            var personalTitle = personalTitleId == null ? null : partyControl.convertPersonalTitleIdToEntity(personalTitleId, EntityPermission.READ_ONLY);
239            var firstName = edit.getFirstName();
240            var middleName = edit.getMiddleName();
241            var lastName = edit.getLastName();
242            var nameSuffixId = edit.getNameSuffixId();
243            var nameSuffix = nameSuffixId == null ? null : partyControl.convertNameSuffixIdToEntity(nameSuffixId, EntityPermission.READ_ONLY);
244            var name = edit.getName();
245            var number = edit.getNumber();
246            var securityCode = edit.getSecurityCode();
247            var strExpirationMonth = edit.getExpirationMonth();
248            var expirationMonth = strExpirationMonth != null? Integer.valueOf(strExpirationMonth): null;
249            var strExpirationYear = edit.getExpirationYear();
250            var expirationYear = strExpirationYear != null? Integer.valueOf(strExpirationYear): null;
251            var billingContactMechanismName = edit.getBillingContactMechanismName();
252            var billingContactMechanism = billingContactMechanismName == null ? null : contactControl.getContactMechanismByName(billingContactMechanismName);
253            var billingPartyContactMechanism = billingContactMechanism == null? null: contactControl.getPartyContactMechanism(party, billingContactMechanism);
254            var issuerName = edit.getIssuerName();
255            var issuerContactMechanismName = edit.getIssuerContactMechanismName();
256            var issuerContactMechanism = issuerContactMechanismName == null ? null : contactControl.getContactMechanismByName(issuerContactMechanismName);
257            var issuerPartyContactMechanism = issuerContactMechanism == null? null: contactControl.getPartyContactMechanism(party, issuerContactMechanism);
258            var partyPaymentMethodCreditCardValue = partyPaymentMethodControl.getPartyPaymentMethodCreditCardValueForUpdate(partyPaymentMethod);
259            var partyPaymentMethodCreditCardSecurityCode = partyPaymentMethodControl.getPartyPaymentMethodCreditCardSecurityCodeForUpdate(partyPaymentMethod);
260
261            String firstNameSdx;
262            try {
263                firstNameSdx = firstName == null ? null : soundex.encode(firstName);
264            } catch(IllegalArgumentException iae) {
265                firstNameSdx = null;
266            }
267
268            String middleNameSdx;
269            try {
270                middleNameSdx = middleName == null ? null : soundex.encode(middleName);
271            } catch(IllegalArgumentException iae) {
272                middleNameSdx = null;
273            }
274
275            String lastNameSdx;
276            try {
277                lastNameSdx = lastName == null ? null : soundex.encode(lastName);
278            } catch(IllegalArgumentException iae) {
279                lastNameSdx = null;
280            }
281
282            partyPaymentMethodCreditCardValue.setNumber(partyPaymentMethodControl.encodePartyPaymentMethodCreditCardNumber(number));
283            partyPaymentMethodCreditCardValue.setExpirationMonth(expirationMonth);
284            partyPaymentMethodCreditCardValue.setExpirationYear(expirationYear);
285            partyPaymentMethodCreditCardValue.setPersonalTitlePK(personalTitle == null? null: personalTitle.getPrimaryKey());
286            partyPaymentMethodCreditCardValue.setFirstName(firstName);
287            partyPaymentMethodCreditCardValue.setFirstNameSdx(firstNameSdx);
288            partyPaymentMethodCreditCardValue.setMiddleName(middleName);
289            partyPaymentMethodCreditCardValue.setMiddleNameSdx(middleNameSdx);
290            partyPaymentMethodCreditCardValue.setLastName(lastName);
291            partyPaymentMethodCreditCardValue.setLastNameSdx(lastNameSdx);
292            partyPaymentMethodCreditCardValue.setNameSuffixPK(nameSuffix == null? null: nameSuffix.getPrimaryKey());
293            partyPaymentMethodCreditCardValue.setName(name);
294            partyPaymentMethodCreditCardValue.setBillingPartyContactMechanismPK(billingPartyContactMechanism == null? null: billingPartyContactMechanism.getPrimaryKey());
295            partyPaymentMethodCreditCardValue.setIssuerName(issuerName);
296            partyPaymentMethodCreditCardValue.setIssuerPartyContactMechanismPK(issuerPartyContactMechanism == null? null: issuerPartyContactMechanism.getPrimaryKey());
297
298            partyPaymentMethodControl.updatePartyPaymentMethodCreditCardFromValue(partyPaymentMethodCreditCardValue, executingPartyPK);
299
300            if(partyPaymentMethodCreditCardSecurityCode == null && securityCode != null) {
301                partyPaymentMethodControl.createPartyPaymentMethodCreditCardSecurityCode(partyPaymentMethod, securityCode, executingPartyPK);
302            } else {
303                if(partyPaymentMethodCreditCardSecurityCode != null && securityCode == null) {
304                    partyPaymentMethodControl.deletePartyPaymentMethodCreditCardSecurityCode(partyPaymentMethodCreditCardSecurityCode, executingPartyPK);
305                } else {
306                    if(partyPaymentMethodCreditCardSecurityCode != null && securityCode != null) {
307                        var partyPaymentMethodCreditCardSecurityCodeValue = partyPaymentMethodControl.getPartyPaymentMethodCreditCardSecurityCodeValueForUpdate(partyPaymentMethod);
308
309                        partyPaymentMethodCreditCardSecurityCodeValue.setSecurityCode(partyPaymentMethodControl.encodePartyPaymentMethodCreditCardSecurityCodeSecurityCode(securityCode));
310                        partyPaymentMethodControl.updatePartyPaymentMethodCreditCardSecurityCodeFromValue(partyPaymentMethodCreditCardSecurityCodeValue, executingPartyPK);
311                    }
312                }
313            }
314        }
315    }
316
317}