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