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.customer.server.command;
018
019import com.echothree.control.user.customer.common.edit.CustomerEdit;
020import com.echothree.control.user.customer.common.edit.CustomerEditFactory;
021import com.echothree.control.user.customer.common.form.EditCustomerForm;
022import com.echothree.control.user.customer.common.result.CustomerResultFactory;
023import com.echothree.control.user.customer.common.result.EditCustomerResult;
024import com.echothree.control.user.customer.common.spec.CustomerSpec;
025import com.echothree.model.control.accounting.common.AccountingConstants;
026import com.echothree.model.control.accounting.server.control.AccountingControl;
027import com.echothree.model.control.cancellationpolicy.common.CancellationKinds;
028import com.echothree.model.control.cancellationpolicy.server.control.CancellationPolicyControl;
029import com.echothree.model.control.customer.server.control.CustomerControl;
030import com.echothree.model.control.party.server.control.PartyControl;
031import com.echothree.model.control.returnpolicy.common.ReturnKinds;
032import com.echothree.model.control.returnpolicy.server.control.ReturnPolicyControl;
033import com.echothree.model.data.accounting.server.entity.Currency;
034import com.echothree.model.data.accounting.server.entity.GlAccount;
035import com.echothree.model.data.cancellationpolicy.server.entity.CancellationPolicy;
036import com.echothree.model.data.customer.server.entity.Customer;
037import com.echothree.model.data.customer.server.entity.CustomerType;
038import com.echothree.model.data.party.server.entity.DateTimeFormat;
039import com.echothree.model.data.party.server.entity.Language;
040import com.echothree.model.data.party.server.entity.Party;
041import com.echothree.model.data.party.server.entity.TimeZone;
042import com.echothree.model.data.party.server.value.PartyGroupValue;
043import com.echothree.model.data.party.server.value.PersonValue;
044import com.echothree.model.data.returnpolicy.server.entity.ReturnPolicy;
045import com.echothree.model.data.user.common.pk.UserVisitPK;
046import com.echothree.util.common.command.EditMode;
047import com.echothree.util.common.message.ExecutionErrors;
048import com.echothree.util.common.validation.FieldDefinition;
049import com.echothree.util.common.validation.FieldType;
050import com.echothree.util.server.control.BaseAbstractEditCommand;
051import com.echothree.util.server.persistence.EntityPermission;
052import com.echothree.util.server.persistence.Session;
053import java.util.Arrays;
054import java.util.Collections;
055import java.util.List;
056import org.apache.commons.codec.language.Soundex;
057
058public class EditCustomerCommand
059        extends BaseAbstractEditCommand<CustomerSpec, CustomerEdit, EditCustomerResult, Party, Party> {
060    
061    private final static List<FieldDefinition> SPEC_FIELD_DEFINITIONS;
062    private final static List<FieldDefinition> EDIT_FIELD_DEFINITIONS;
063    
064    static {
065        SPEC_FIELD_DEFINITIONS = Collections.unmodifiableList(Arrays.asList(
066                new FieldDefinition("CustomerName", FieldType.ENTITY_NAME, true, null, null)
067                ));
068        
069        EDIT_FIELD_DEFINITIONS = Collections.unmodifiableList(Arrays.asList(
070                new FieldDefinition("CustomerTypeName", FieldType.ENTITY_NAME, true, null, null),
071                new FieldDefinition("CancellationPolicyName", FieldType.ENTITY_NAME, false, null, null),
072                new FieldDefinition("ReturnPolicyName", FieldType.ENTITY_NAME, false, null, null),
073                new FieldDefinition("ArGlAccountName", FieldType.ENTITY_NAME, false, null, null),
074                new FieldDefinition("PersonalTitleId", FieldType.ID, false, null, null),
075                new FieldDefinition("FirstName", FieldType.STRING, false, 1L, 20L),
076                new FieldDefinition("MiddleName", FieldType.STRING, false, 1L, 20L),
077                new FieldDefinition("LastName", FieldType.STRING, false, 1L, 20L),
078                new FieldDefinition("NameSuffixId", FieldType.ID, false, null, null),
079                new FieldDefinition("Name", FieldType.STRING, false, 1L, 60L),
080                new FieldDefinition("PreferredLanguageIsoName", FieldType.ENTITY_NAME, false, null, null),
081                new FieldDefinition("PreferredCurrencyIsoName", FieldType.ENTITY_NAME, false, null, null),
082                new FieldDefinition("PreferredJavaTimeZoneName", FieldType.TIME_ZONE_NAME, false, null, null),
083                new FieldDefinition("PreferredDateTimeFormatName", FieldType.ENTITY_NAME, false, null, null),
084                new FieldDefinition("HoldUntilComplete", FieldType.BOOLEAN, true, null, null),
085                new FieldDefinition("AllowBackorders", FieldType.BOOLEAN, true, null, null),
086                new FieldDefinition("AllowSubstitutions", FieldType.BOOLEAN, true, null, null),
087                new FieldDefinition("AllowCombiningShipments", FieldType.BOOLEAN, true, null, null),
088                new FieldDefinition("RequireReference", FieldType.BOOLEAN, true, null, null),
089                new FieldDefinition("AllowReferenceDuplicates", FieldType.BOOLEAN, true, null, null),
090                new FieldDefinition("ReferenceValidationPattern", FieldType.REGULAR_EXPRESSION, false, null, null)
091                ));
092    }
093    
094    /** Creates a new instance of EditCustomerCommand */
095    public EditCustomerCommand(UserVisitPK userVisitPK, EditCustomerForm form) {
096        super(userVisitPK, form, null, SPEC_FIELD_DEFINITIONS, EDIT_FIELD_DEFINITIONS);
097    }
098
099    @Override
100    public EditCustomerResult getResult() {
101        return CustomerResultFactory.getEditCustomerResult();
102    }
103
104    @Override
105    public CustomerEdit getEdit() {
106        return CustomerEditFactory.getCustomerEdit();
107    }
108
109    @Override
110    public Party getEntity(EditCustomerResult result) {
111        var customerControl = Session.getModelController(CustomerControl.class);
112        Customer customer;
113        var customerName = spec.getCustomerName();
114
115        if(editMode.equals(EditMode.LOCK) || editMode.equals(EditMode.ABANDON)) {
116            customer = customerControl.getCustomerByName(customerName);
117        } else { // EditMode.UPDATE
118            customer = customerControl.getCustomerByNameForUpdate(customerName);
119        }
120
121        if(customer != null) {
122            result.setCustomer(customerControl.getCustomerTransfer(getUserVisit(), customer));
123        } else {
124            addExecutionError(ExecutionErrors.UnknownCustomerName.name(), customerName);
125        }
126
127        return customer.getParty();
128    }
129
130    @Override
131    public Party getLockEntity(Party party) {
132        return party;
133    }
134
135    @Override
136    public void fillInResult(EditCustomerResult result, Party party) {
137        var customerControl = Session.getModelController(CustomerControl.class);
138
139        result.setCustomer(customerControl.getCustomerTransfer(getUserVisit(), party));
140    }
141
142    @Override
143    public void doLock(CustomerEdit edit, Party party) {
144        var customerControl = Session.getModelController(CustomerControl.class);
145        var partyControl = Session.getModelController(PartyControl.class);
146        var customer = customerControl.getCustomer(party);
147        var partyDetail = party.getLastDetail();
148        var partyGroup = partyControl.getPartyGroup(party);
149        var arGlAccount = customer.getArGlAccount();
150        var cancellationPolicy = customer.getCancellationPolicy();
151        var returnPolicy = customer.getReturnPolicy();
152        var preferredLanguage = partyDetail.getPreferredLanguage();
153        var preferredCurrency = partyDetail.getPreferredCurrency();
154        var preferredTimeZone = partyDetail.getPreferredTimeZone();
155        var dateTimeFormat = partyDetail.getPreferredDateTimeFormat();
156        var person = partyControl.getPerson(party);
157        var personalTitle = person == null ? null : person.getPersonalTitle();
158        var nameSuffix = person == null ? null : person.getNameSuffix();
159
160        edit.setCustomerTypeName(customer.getCustomerType().getLastDetail().getCustomerTypeName());
161        edit.setPersonalTitleId(personalTitle == null ? null : personalTitle.getPrimaryKey().getEntityId().toString());
162        edit.setFirstName(person == null ? null : person.getFirstName());
163        edit.setMiddleName(person == null ? null : person.getMiddleName());
164        edit.setLastName(person == null ? null : person.getLastName());
165        edit.setNameSuffixId(nameSuffix == null ? null : nameSuffix.getPrimaryKey().getEntityId().toString());
166        edit.setName(partyGroup == null ? null : partyGroup.getName());
167        edit.setPreferredLanguageIsoName(preferredLanguage == null ? null : preferredLanguage.getLanguageIsoName());
168        edit.setPreferredCurrencyIsoName(preferredCurrency == null ? null : preferredCurrency.getCurrencyIsoName());
169        edit.setPreferredJavaTimeZoneName(preferredTimeZone == null ? null : preferredTimeZone.getLastDetail().getJavaTimeZoneName());
170        edit.setPreferredDateTimeFormatName(dateTimeFormat == null ? null : dateTimeFormat.getLastDetail().getDateTimeFormatName());
171        edit.setArGlAccountName(arGlAccount == null ? null : arGlAccount.getLastDetail().getGlAccountName());
172        edit.setCancellationPolicyName(cancellationPolicy == null ? null : cancellationPolicy.getLastDetail().getCancellationPolicyName());
173        edit.setReturnPolicyName(returnPolicy == null ? null : returnPolicy.getLastDetail().getReturnPolicyName());
174        edit.setHoldUntilComplete(customer.getHoldUntilComplete().toString());
175        edit.setAllowBackorders(customer.getAllowBackorders().toString());
176        edit.setAllowSubstitutions(customer.getAllowSubstitutions().toString());
177        edit.setAllowCombiningShipments(customer.getAllowCombiningShipments().toString());
178        edit.setRequireReference(customer.getRequireReference().toString());
179        edit.setAllowReferenceDuplicates(customer.getAllowReferenceDuplicates().toString());
180        edit.setReferenceValidationPattern(customer.getReferenceValidationPattern());
181    }
182
183    CustomerType customerType;
184    CancellationPolicy cancellationPolicy;
185    ReturnPolicy returnPolicy;
186    GlAccount arGlAccount;
187    Language preferredLanguage;
188    TimeZone preferredTimeZone;
189    DateTimeFormat preferredDateTimeFormat;
190    Currency preferredCurrency;
191
192    @Override
193    public void canUpdate(Party party) {
194        var customerControl = Session.getModelController(CustomerControl.class);
195        var partyControl = Session.getModelController(PartyControl.class);
196        var customerTypeName = edit.getCustomerTypeName();
197
198        customerType = customerControl.getCustomerTypeByName(customerTypeName);
199
200        if(customerType != null) {
201            var cancellationPolicyName = edit.getCancellationPolicyName();
202
203            if(cancellationPolicyName != null) {
204                var cancellationPolicyControl = Session.getModelController(CancellationPolicyControl.class);
205                var cancellationKind = cancellationPolicyControl.getCancellationKindByName(CancellationKinds.CUSTOMER_CANCELLATION.name());
206
207                cancellationPolicy = cancellationPolicyControl.getCancellationPolicyByName(cancellationKind, cancellationPolicyName);
208            }
209
210            if(cancellationPolicyName == null || cancellationPolicy != null) {
211                var returnPolicyName = edit.getReturnPolicyName();
212
213                if(returnPolicyName != null) {
214                    var returnPolicyControl = Session.getModelController(ReturnPolicyControl.class);
215                    var returnKind = returnPolicyControl.getReturnKindByName(ReturnKinds.CUSTOMER_RETURN.name());
216
217                    returnPolicy = returnPolicyControl.getReturnPolicyByName(returnKind, returnPolicyName);
218                }
219
220                if(returnPolicyName == null || returnPolicy != null) {
221                    var accountingControl = Session.getModelController(AccountingControl.class);
222                    var arGlAccountName = edit.getArGlAccountName();
223
224                    arGlAccount = arGlAccountName == null ? null : accountingControl.getGlAccountByName(arGlAccountName);
225
226                    if(arGlAccountName == null || arGlAccount != null) {
227                        var glAccountCategoryName = arGlAccount == null ? null : arGlAccount.getLastDetail().getGlAccountCategory().getLastDetail().getGlAccountCategoryName();
228
229                        if(glAccountCategoryName == null || glAccountCategoryName.equals(AccountingConstants.GlAccountCategory_ACCOUNTS_RECEIVABLE)) {
230                            var preferredLanguageIsoName = edit.getPreferredLanguageIsoName();
231
232                            preferredLanguage = preferredLanguageIsoName == null ? null : partyControl.getLanguageByIsoName(preferredLanguageIsoName);
233
234                            if(preferredLanguageIsoName == null || (preferredLanguage != null)) {
235                                var preferredJavaTimeZoneName = edit.getPreferredJavaTimeZoneName();
236
237                                preferredTimeZone = preferredJavaTimeZoneName == null ? null : partyControl.getTimeZoneByJavaName(preferredJavaTimeZoneName);
238
239                                if(preferredJavaTimeZoneName == null || (preferredTimeZone != null)) {
240                                    var preferredDateTimeFormatName = edit.getPreferredDateTimeFormatName();
241
242                                    preferredDateTimeFormat = preferredDateTimeFormatName == null ? null : partyControl.getDateTimeFormatByName(preferredDateTimeFormatName);
243
244                                    if(preferredDateTimeFormatName == null || (preferredDateTimeFormat != null)) {
245                                        var preferredCurrencyIsoName = edit.getPreferredCurrencyIsoName();
246
247                                        if(preferredCurrencyIsoName == null) {
248                                            preferredCurrency = null;
249                                        } else {
250                                            preferredCurrency = accountingControl.getCurrencyByIsoName(preferredCurrencyIsoName);
251                                        }
252
253                                        if(preferredCurrencyIsoName != null && (preferredCurrency == null)) {
254                                            addExecutionError(ExecutionErrors.UnknownCurrencyIsoName.name(), preferredCurrencyIsoName);
255                                        }
256                                    } else {
257                                        addExecutionError(ExecutionErrors.UnknownDateTimeFormatName.name(), preferredDateTimeFormatName);
258                                    }
259                                } else {
260                                    addExecutionError(ExecutionErrors.UnknownJavaTimeZoneName.name(), preferredJavaTimeZoneName);
261                                }
262                            } else {
263                                addExecutionError(ExecutionErrors.UnknownLanguageIsoName.name(), preferredLanguageIsoName);
264                            }
265                        } else {
266                            addExecutionError(ExecutionErrors.InvalidGlAccountCategory.name(), glAccountCategoryName);
267                        }
268                    } else {
269                        addExecutionError(ExecutionErrors.UnknownArGlAccountName.name(), arGlAccountName);
270                    }
271                } else {
272                    addExecutionError(ExecutionErrors.UnknownReturnPolicyName.name(), returnPolicyName);
273                }
274            } else {
275                addExecutionError(ExecutionErrors.UnknownCancellationPolicyName.name(), cancellationPolicyName);
276            }
277        } else {
278            addExecutionError(ExecutionErrors.UnknownCustomerTypeName.name(), customerTypeName);
279        }
280    }
281
282    @Override
283    public void doUpdate(Party party) {
284        var customerControl = Session.getModelController(CustomerControl.class);
285        var partyControl = Session.getModelController(PartyControl.class);
286        var soundex = new Soundex();
287        var partyDetailValue = partyControl.getPartyDetailValueForUpdate(party);
288        var customer = customerControl.getCustomerForUpdate(party);
289        var customerValue = customerControl.getCustomerValue(customer);
290        var partyGroup = partyControl.getPartyGroupForUpdate(party);
291        var person = partyControl.getPersonForUpdate(party);
292        var personalTitleId = edit.getPersonalTitleId();
293        var personalTitle = personalTitleId == null ? null : partyControl.convertPersonalTitleIdToEntity(personalTitleId, EntityPermission.READ_ONLY);
294        var firstName = edit.getFirstName();
295        var firstNameSdx = soundex.encode(firstName);
296        var middleName = edit.getMiddleName();
297        var middleNameSdx = middleName == null ? null : soundex.encode(middleName);
298        var lastName = edit.getLastName();
299        var lastNameSdx = soundex.encode(lastName);
300        var nameSuffixId = edit.getNameSuffixId();
301        var nameSuffix = nameSuffixId == null ? null : partyControl.convertNameSuffixIdToEntity(nameSuffixId, EntityPermission.READ_ONLY);
302        var name = edit.getName();
303        var updatedBy = getPartyPK();
304
305        customerValue.setCustomerTypePK(customerType.getPrimaryKey());
306        customerValue.setArGlAccountPK(arGlAccount == null ? null : arGlAccount.getPrimaryKey());
307        customerValue.setCancellationPolicyPK(cancellationPolicy == null ? null : cancellationPolicy.getPrimaryKey());
308        customerValue.setReturnPolicyPK(returnPolicy == null ? null : returnPolicy.getPrimaryKey());
309        customerValue.setHoldUntilComplete(Boolean.valueOf(edit.getHoldUntilComplete()));
310        customerValue.setAllowBackorders(Boolean.valueOf(edit.getAllowBackorders()));
311        customerValue.setAllowSubstitutions(Boolean.valueOf(edit.getAllowSubstitutions()));
312        customerValue.setAllowCombiningShipments(Boolean.valueOf(edit.getAllowCombiningShipments()));
313        customerValue.setRequireReference(Boolean.valueOf(edit.getRequireReference()));
314        customerValue.setAllowReferenceDuplicates(Boolean.valueOf(edit.getAllowReferenceDuplicates()));
315        customerValue.setReferenceValidationPattern(edit.getReferenceValidationPattern());
316
317        partyDetailValue.setPreferredLanguagePK(preferredLanguage == null ? null : preferredLanguage.getPrimaryKey());
318        partyDetailValue.setPreferredTimeZonePK(preferredTimeZone == null ? null : preferredTimeZone.getPrimaryKey());
319        partyDetailValue.setPreferredDateTimeFormatPK(preferredDateTimeFormat == null ? null : preferredDateTimeFormat.getPrimaryKey());
320        partyDetailValue.setPreferredCurrencyPK(preferredCurrency == null ? null : preferredCurrency.getPrimaryKey());
321
322        if(name != null) {
323            if(partyGroup != null) {
324                PartyGroupValue partyGroupValue = partyControl.getPartyGroupValue(partyGroup);
325
326                partyGroupValue.setName(name);
327                partyControl.updatePartyGroupFromValue(partyGroupValue, updatedBy);
328            } else {
329                partyControl.createPartyGroup(party, name, updatedBy);
330            }
331        } else {
332            if(partyGroup != null) {
333                partyControl.deletePartyGroup(partyGroup, updatedBy);
334            }
335        }
336
337        if(personalTitle != null || firstName != null || middleName != null || lastName != null || nameSuffix != null) {
338            if(person != null) {
339                PersonValue personValue = partyControl.getPersonValue(person);
340
341                personValue.setPersonalTitlePK(personalTitle == null ? null : personalTitle.getPrimaryKey());
342                personValue.setFirstName(firstName);
343                personValue.setFirstNameSdx(firstNameSdx);
344                personValue.setMiddleName(middleName);
345                personValue.setMiddleNameSdx(middleNameSdx);
346                personValue.setLastName(lastName);
347                personValue.setLastNameSdx(lastNameSdx);
348                personValue.setNameSuffixPK(nameSuffix == null ? null : nameSuffix.getPrimaryKey());
349                partyControl.updatePersonFromValue(personValue, updatedBy);
350            } else {
351                partyControl.createPerson(party, personalTitle, firstName, firstNameSdx, middleName, middleNameSdx,
352                        lastName, lastNameSdx, nameSuffix, updatedBy);
353            }
354        } else {
355            if(person != null) {
356                partyControl.deletePerson(person, updatedBy);
357            }
358        }
359
360        customerControl.updateCustomerFromValue(customerValue, updatedBy);
361        partyControl.updatePartyFromValue(partyDetailValue, updatedBy);
362    }
363
364}