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