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