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.geo.server.command;
018
019import com.echothree.control.user.geo.common.edit.CountryEdit;
020import com.echothree.control.user.geo.common.edit.GeoEditFactory;
021import com.echothree.control.user.geo.common.form.EditCountryForm;
022import com.echothree.control.user.geo.common.result.EditCountryResult;
023import com.echothree.control.user.geo.common.result.GeoResultFactory;
024import com.echothree.control.user.geo.common.spec.GeoCodeSpec;
025import com.echothree.model.control.contact.server.control.ContactControl;
026import com.echothree.model.control.geo.common.GeoConstants;
027import com.echothree.model.control.geo.server.control.GeoControl;
028import com.echothree.model.control.geo.server.logic.GeoCodeAliasLogic;
029import com.echothree.model.control.geo.server.logic.GeoCodeLogic;
030import com.echothree.model.control.geo.server.logic.GeoCodeScopeLogic;
031import com.echothree.model.control.geo.server.logic.GeoCodeTypeLogic;
032import com.echothree.model.control.party.common.PartyTypes;
033import com.echothree.model.control.security.common.SecurityRoleGroups;
034import com.echothree.model.control.security.common.SecurityRoles;
035import com.echothree.model.data.contact.server.entity.PostalAddressFormat;
036import com.echothree.model.data.geo.server.entity.GeoCode;
037import com.echothree.model.data.geo.server.entity.GeoCodeAlias;
038import com.echothree.model.data.geo.server.entity.GeoCodeCountry;
039import com.echothree.model.data.geo.server.entity.GeoCodeDescription;
040import com.echothree.model.data.geo.server.entity.GeoCodeDetail;
041import com.echothree.model.data.geo.server.entity.GeoCodeScope;
042import com.echothree.model.data.geo.server.entity.GeoCodeType;
043import com.echothree.model.data.geo.server.value.GeoCodeAliasValue;
044import com.echothree.model.data.geo.server.value.GeoCodeCountryValue;
045import com.echothree.model.data.geo.server.value.GeoCodeDescriptionValue;
046import com.echothree.model.data.geo.server.value.GeoCodeDetailValue;
047import com.echothree.model.data.user.common.pk.UserVisitPK;
048import com.echothree.util.common.command.EditMode;
049import com.echothree.util.common.message.ExecutionErrors;
050import com.echothree.util.common.validation.FieldDefinition;
051import com.echothree.util.common.validation.FieldType;
052import com.echothree.util.server.control.BaseAbstractEditCommand;
053import com.echothree.util.server.control.CommandSecurityDefinition;
054import com.echothree.util.server.control.PartyTypeDefinition;
055import com.echothree.util.server.control.SecurityRoleDefinition;
056import com.echothree.util.server.persistence.Session;
057import java.util.Arrays;
058import java.util.Collections;
059import java.util.List;
060
061public class EditCountryCommand
062        extends BaseAbstractEditCommand<GeoCodeSpec, CountryEdit, EditCountryResult, GeoCode, GeoCode> {
063
064    private final static CommandSecurityDefinition COMMAND_SECURITY_DEFINITION;
065    private final static List<FieldDefinition> SPEC_FIELD_DEFINITIONS;
066    private final static List<FieldDefinition> EDIT_FIELD_DEFINITIONS;
067
068    static {
069        COMMAND_SECURITY_DEFINITION = new CommandSecurityDefinition(Collections.unmodifiableList(Arrays.asList(
070                new PartyTypeDefinition(PartyTypes.UTILITY.name(), null),
071                new PartyTypeDefinition(PartyTypes.EMPLOYEE.name(), Collections.unmodifiableList(Arrays.asList(
072                    new SecurityRoleDefinition(SecurityRoleGroups.Country.name(), SecurityRoles.Edit.name())
073                    )))
074                )));
075
076        SPEC_FIELD_DEFINITIONS = Collections.unmodifiableList(Arrays.asList(
077                new FieldDefinition("GeoCodeName", FieldType.ENTITY_NAME, true, null, null)
078                ));
079
080        EDIT_FIELD_DEFINITIONS = Collections.unmodifiableList(Arrays.asList(
081                new FieldDefinition("CountryName", FieldType.ENTITY_NAME, true, null, null),
082                new FieldDefinition("Iso3Number", FieldType.NUMBER_3, true, null, null),
083                new FieldDefinition("Iso3Letter", FieldType.UPPER_LETTER_3, true, null, null),
084                new FieldDefinition("Iso2Letter", FieldType.UPPER_LETTER_2, true, null, null),
085                new FieldDefinition("TelephoneCode", FieldType.STRING, false, 1L, 5L),
086                new FieldDefinition("AreaCodePattern", FieldType.REGULAR_EXPRESSION, false, null, null),
087                new FieldDefinition("AreaCodeRequired", FieldType.BOOLEAN, true, null, null),
088                new FieldDefinition("AreaCodeExample", FieldType.STRING, false, 1L, 5L),
089                new FieldDefinition("TelephoneNumberPattern", FieldType.REGULAR_EXPRESSION, false, null, null),
090                new FieldDefinition("TelephoneNumberExample", FieldType.STRING, false, 1L, 25L),
091                new FieldDefinition("PostalAddressFormatName", FieldType.ENTITY_NAME, true, null, null),
092                new FieldDefinition("CityRequired", FieldType.BOOLEAN, true, null, null),
093                new FieldDefinition("CityGeoCodeRequired", FieldType.BOOLEAN, true, null, null),
094                new FieldDefinition("StateRequired", FieldType.BOOLEAN, true, null, null),
095                new FieldDefinition("StateGeoCodeRequired", FieldType.BOOLEAN, true, null, null),
096                new FieldDefinition("PostalCodePattern", FieldType.REGULAR_EXPRESSION, false, null, null),
097                new FieldDefinition("PostalCodeRequired", FieldType.BOOLEAN, true, null, null),
098                new FieldDefinition("PostalCodeGeoCodeRequired", FieldType.BOOLEAN, true, null, null),
099                new FieldDefinition("PostalCodeLength", FieldType.UNSIGNED_INTEGER, false, null, null),
100                new FieldDefinition("PostalCodeGeoCodeLength", FieldType.UNSIGNED_INTEGER, false, null, null),
101                new FieldDefinition("PostalCodeExample", FieldType.STRING, false, 1L, 15L),
102                new FieldDefinition("IsDefault", FieldType.BOOLEAN, true, null, null),
103                new FieldDefinition("SortOrder", FieldType.SIGNED_INTEGER, true, null, null),
104                new FieldDefinition("Description", FieldType.STRING, false, 1L, 132L)
105                ));
106    }
107
108    /** Creates a new instance of EditCountryCommand */
109    public EditCountryCommand(UserVisitPK userVisitPK, EditCountryForm form) {
110        super(userVisitPK, form, COMMAND_SECURITY_DEFINITION, SPEC_FIELD_DEFINITIONS, EDIT_FIELD_DEFINITIONS);
111    }
112
113    @Override
114    public EditCountryResult getResult() {
115        return GeoResultFactory.getEditCountryResult();
116    }
117
118    @Override
119    public CountryEdit getEdit() {
120        return GeoEditFactory.getCountryEdit();
121    }
122
123    @Override
124    public GeoCode getEntity(EditCountryResult result) {
125        var geoControl = Session.getModelController(GeoControl.class);
126        GeoCode geoCode = null;
127        String geoCodeName = spec.getGeoCodeName();
128
129        if(editMode.equals(EditMode.LOCK) || editMode.equals(EditMode.ABANDON)) {
130            geoCode = geoControl.getGeoCodeByName(geoCodeName);
131        } else { // EditMode.UPDATE
132            geoCode = geoControl.getGeoCodeByNameForUpdate(geoCodeName);
133        }
134
135        if(geoCode != null) {
136            String geoCodeTypeName = geoCode.getLastDetail().getGeoCodeType().getLastDetail().getGeoCodeTypeName();
137            
138            if(!geoCodeTypeName.equals(GeoConstants.GeoCodeType_COUNTRY)) {
139                addExecutionError(ExecutionErrors.InvalidGeoCodeType.name(), geoCodeTypeName);
140            }
141        } else {
142            addExecutionError(ExecutionErrors.UnknownGeoCodeName.name(), geoCodeName);
143        }
144
145        return geoCode;
146    }
147
148    @Override
149    public GeoCode getLockEntity(GeoCode geoCode) {
150        return geoCode;
151    }
152
153    @Override
154    public void fillInResult(EditCountryResult result, GeoCode geoCode) {
155        var geoControl = Session.getModelController(GeoControl.class);
156
157        result.setCountry(geoControl.getCountryTransfer(getUserVisit(), geoCode));
158    }
159
160    @Override
161    public void doLock(CountryEdit edit, GeoCode geoCode) {
162        var geoControl = Session.getModelController(GeoControl.class);
163        var geoCodeAliasLogic = GeoCodeAliasLogic.getInstance();
164        GeoCodeDescription geoCodeDescription = geoControl.getGeoCodeDescription(geoCode, getPreferredLanguage());
165        GeoCodeDetail geoCodeDetail = geoCode.getLastDetail();
166        GeoCodeCountry geoCodeCountry = geoControl.getGeoCodeCountry(geoCode);
167        Integer postalCodeLength = geoCodeCountry.getPostalCodeGeoCodeLength();
168        Integer postalCodeGeoCodeLength = geoCodeCountry.getPostalCodeGeoCodeLength();
169
170        GeoCodeAlias geoCodeAlias = geoCodeAliasLogic.getGeoCodeAliasUsingNames(null, geoCode, GeoConstants.GeoCodeAliasType_COUNTRY_NAME);
171        edit.setCountryName(geoCodeAlias.getAlias());
172
173        geoCodeAlias = geoCodeAliasLogic.getGeoCodeAliasUsingNames(null, geoCode, GeoConstants.GeoCodeAliasType_ISO_3_NUMBER);
174        edit.setIso3Number(geoCodeAlias.getAlias());
175
176        geoCodeAlias = geoCodeAliasLogic.getGeoCodeAliasUsingNames(null, geoCode, GeoConstants.GeoCodeAliasType_ISO_3_LETTER);
177        edit.setIso3Letter(geoCodeAlias.getAlias());
178
179        geoCodeAlias = geoCodeAliasLogic.getGeoCodeAliasUsingNames(null, geoCode, GeoConstants.GeoCodeAliasType_ISO_2_LETTER);
180        edit.setIso2Letter(geoCodeAlias.getAlias());
181
182        edit.setTelephoneCode(geoCodeCountry.getTelephoneCode());
183        edit.setAreaCodePattern(geoCodeCountry.getAreaCodePattern());
184        edit.setAreaCodeRequired(geoCodeCountry.getAreaCodeRequired().toString());
185        edit.setAreaCodeExample(geoCodeCountry.getAreaCodeExample());
186        edit.setTelephoneNumberPattern(geoCodeCountry.getTelephoneNumberPattern());
187        edit.setTelephoneNumberExample(geoCodeCountry.getTelephoneNumberExample());
188        edit.setPostalAddressFormatName(geoCodeCountry.getPostalAddressFormat().getLastDetail().getPostalAddressFormatName());
189        edit.setCityRequired(geoCodeCountry.getCityRequired().toString());
190        edit.setCityGeoCodeRequired(geoCodeCountry.getCityGeoCodeRequired().toString());
191        edit.setStateRequired(geoCodeCountry.getStateRequired().toString());
192        edit.setStateGeoCodeRequired(geoCodeCountry.getStateGeoCodeRequired().toString());
193        edit.setPostalCodePattern(geoCodeCountry.getPostalCodePattern());
194        edit.setPostalCodeRequired(geoCodeCountry.getPostalCodeRequired().toString());
195        edit.setPostalCodeGeoCodeRequired(geoCodeCountry.getPostalCodeGeoCodeRequired().toString());
196        edit.setPostalCodeLength(postalCodeLength == null ? null : postalCodeLength.toString());
197        edit.setPostalCodeGeoCodeLength(postalCodeGeoCodeLength == null ? null : postalCodeGeoCodeLength.toString());
198        edit.setPostalCodeExample(geoCodeCountry.getPostalCodeExample());
199        edit.setIsDefault(geoCodeDetail.getIsDefault().toString());
200        edit.setSortOrder(geoCodeDetail.getSortOrder().toString());
201
202        if(geoCodeDescription != null) {
203            edit.setDescription(geoCodeDescription.getDescription());
204        }
205    }
206
207    PostalAddressFormat postalAddressFormat;
208
209    @Override
210    public void canUpdate(GeoCode geoCode) {
211        var geoCodeTypeLogic = GeoCodeTypeLogic.getInstance();
212        GeoCodeType geoCodeType = geoCodeTypeLogic.getGeoCodeTypeByName(this, GeoConstants.GeoCodeType_COUNTRY);
213
214        if(!hasExecutionErrors()) {
215            var geoCodeScopeLogic = GeoCodeScopeLogic.getInstance();
216            GeoCodeScope geoCodeScope = geoCodeScopeLogic.getGeoCodeScopeByName(this, GeoConstants.GeoCodeScope_COUNTRIES);
217
218            if(!hasExecutionErrors()) {
219                var geoCodeLogic = GeoCodeLogic.getInstance();
220                String iso3Number = edit.getIso3Number();
221                GeoCode duplicateGeoCode = geoCodeLogic.getGeoCodeByAlias(this, geoCodeType, geoCodeScope, GeoConstants.GeoCodeAliasType_ISO_3_NUMBER, iso3Number);
222
223                if((duplicateGeoCode == null || duplicateGeoCode.equals(geoCode)) && !hasExecutionErrors()) {
224                    String iso3Letter = edit.getIso3Letter();
225
226                    duplicateGeoCode = geoCodeLogic.getGeoCodeByAlias(this, geoCodeType, geoCodeScope, GeoConstants.GeoCodeAliasType_ISO_3_LETTER, iso3Letter);
227
228                    if((duplicateGeoCode == null || duplicateGeoCode.equals(geoCode)) && !hasExecutionErrors()) {
229                        String iso2Letter = edit.getIso2Letter();
230
231                        duplicateGeoCode = geoCodeLogic.getGeoCodeByAlias(this, geoCodeType, geoCodeScope, GeoConstants.GeoCodeAliasType_ISO_2_LETTER, iso2Letter);
232
233                        if((duplicateGeoCode == null || duplicateGeoCode.equals(geoCode)) && !hasExecutionErrors()) {
234                            String countryName = edit.getCountryName();
235
236                            duplicateGeoCode = geoCodeLogic.getGeoCodeByAlias(this, geoCodeType, geoCodeScope, GeoConstants.GeoCodeAliasType_COUNTRY_NAME, countryName);
237
238                            if((duplicateGeoCode == null || duplicateGeoCode.equals(geoCode)) && !hasExecutionErrors()) {
239                                var contactControl = Session.getModelController(ContactControl.class);
240                                String postalAddressFormatName = edit.getPostalAddressFormatName();
241
242                                postalAddressFormat = contactControl.getPostalAddressFormatByName(postalAddressFormatName);
243
244                                if(postalAddressFormat == null) {
245                                    addExecutionError(ExecutionErrors.UnknownPostalAddressFormatName.name(), postalAddressFormatName);
246                                }
247                            } else {
248                                if(geoCode != null) {
249                                    addExecutionError(ExecutionErrors.DuplicateCountryName.name(), countryName);
250                                }
251                            }
252                        } else {
253                            if(geoCode != null) {
254                                addExecutionError(ExecutionErrors.DuplicateIso2Letter.name(), iso2Letter);
255                            }
256                        }
257                    } else {
258                        if(geoCode != null) {
259                            addExecutionError(ExecutionErrors.DuplicateIso3Letter.name(), iso3Letter);
260                        }
261                    }
262                } else {
263                    if(geoCode != null) {
264                        addExecutionError(ExecutionErrors.DuplicateIso3Number.name(), iso3Number);
265                    }
266                }
267            }
268        }
269    }
270
271    @Override
272    public void doUpdate(GeoCode geoCode) {
273        var geoControl = Session.getModelController(GeoControl.class);
274        var geoCodeAliasLogic = GeoCodeAliasLogic.getInstance();
275        var partyPK = getPartyPK();
276        GeoCodeDetailValue geoCodeDetailValue = geoControl.getGeoCodeDetailValueForUpdate(geoCode);
277        GeoCodeDescription geoCodeDescription = geoControl.getGeoCodeDescriptionForUpdate(geoCode, getPreferredLanguage());
278        GeoCodeCountryValue geoCodeCountryValue = geoControl.getGeoCodeCountryValueForUpdate(geoCode);
279        String strPostalCodeLength = edit.getPostalCodeLength();
280        Integer postalCodeLength = strPostalCodeLength == null ? null : Integer.valueOf(strPostalCodeLength);
281        String strPostalCodeGeoCodeLength = edit.getPostalCodeGeoCodeLength();
282        Integer postalCodeGeoCodeLength = strPostalCodeGeoCodeLength == null ? null : Integer.valueOf(strPostalCodeGeoCodeLength);
283        String description = edit.getDescription();
284
285        GeoCodeAliasValue geoCodeAliasValue = geoCodeAliasLogic.getGeoCodeAliasValueUsingNames(null, geoCode, GeoConstants.GeoCodeAliasType_COUNTRY_NAME);
286        geoCodeAliasValue.setAlias(edit.getCountryName());
287        geoControl.updateGeoCodeAliasFromValue(geoCodeAliasValue, partyPK);
288
289        geoCodeAliasValue = geoCodeAliasLogic.getGeoCodeAliasValueUsingNames(null, geoCode, GeoConstants.GeoCodeAliasType_ISO_3_NUMBER);
290        geoCodeAliasValue.setAlias(edit.getIso3Number());
291        geoControl.updateGeoCodeAliasFromValue(geoCodeAliasValue, partyPK);
292
293        geoCodeAliasValue = geoCodeAliasLogic.getGeoCodeAliasValueUsingNames(null, geoCode, GeoConstants.GeoCodeAliasType_ISO_3_LETTER);
294        geoCodeAliasValue.setAlias(edit.getIso3Letter());
295        geoControl.updateGeoCodeAliasFromValue(geoCodeAliasValue, partyPK);
296
297        geoCodeAliasValue = geoCodeAliasLogic.getGeoCodeAliasValueUsingNames(null, geoCode, GeoConstants.GeoCodeAliasType_ISO_2_LETTER);
298        geoCodeAliasValue.setAlias(edit.getIso2Letter());
299        geoControl.updateGeoCodeAliasFromValue(geoCodeAliasValue, partyPK);
300
301        geoCodeCountryValue.setTelephoneCode(edit.getTelephoneCode());
302        geoCodeCountryValue.setAreaCodePattern(edit.getAreaCodePattern());
303        geoCodeCountryValue.setAreaCodeRequired(Boolean.valueOf(edit.getAreaCodeRequired()));
304        geoCodeCountryValue.setAreaCodeExample(edit.getAreaCodeExample());
305        geoCodeCountryValue.setTelephoneNumberPattern(edit.getTelephoneNumberPattern());
306        geoCodeCountryValue.setTelephoneNumberExample(edit.getTelephoneNumberExample());
307        geoCodeCountryValue.setPostalAddressFormatPK(postalAddressFormat.getPrimaryKey());
308        geoCodeCountryValue.setCityRequired(Boolean.valueOf(edit.getCityRequired()));
309        geoCodeCountryValue.setCityGeoCodeRequired(Boolean.valueOf(edit.getCityGeoCodeRequired()));
310        geoCodeCountryValue.setStateRequired(Boolean.valueOf(edit.getStateRequired()));
311        geoCodeCountryValue.setStateGeoCodeRequired(Boolean.valueOf(edit.getStateGeoCodeRequired()));
312        geoCodeCountryValue.setPostalCodePattern(edit.getPostalCodePattern());
313        geoCodeCountryValue.setPostalCodeRequired(Boolean.valueOf(edit.getPostalCodeRequired()));
314        geoCodeCountryValue.setPostalCodeGeoCodeRequired(Boolean.valueOf(edit.getPostalCodeGeoCodeRequired()));
315        geoCodeCountryValue.setPostalCodeLength(postalCodeLength);
316        geoCodeCountryValue.setPostalCodeGeoCodeLength(postalCodeGeoCodeLength);
317        geoCodeCountryValue.setPostalCodeExample(edit.getPostalCodeExample());
318        
319        geoCodeDetailValue.setIsDefault(Boolean.valueOf(edit.getIsDefault()));
320        geoCodeDetailValue.setSortOrder(Integer.valueOf(edit.getSortOrder()));
321
322        geoControl.updateGeoCodeFromValue(geoCodeDetailValue, partyPK);
323        geoControl.updateGeoCodeCountryFromValue(geoCodeCountryValue, partyPK);
324
325        if(geoCodeDescription == null && description != null) {
326            geoControl.createGeoCodeDescription(geoCode, getPreferredLanguage(), description, partyPK);
327        } else {
328            if(geoCodeDescription != null && description == null) {
329                geoControl.deleteGeoCodeDescription(geoCodeDescription, partyPK);
330            } else {
331                if(geoCodeDescription != null && description != null) {
332                    GeoCodeDescriptionValue geoCodeDescriptionValue = geoControl.getGeoCodeDescriptionValue(geoCodeDescription);
333
334                    geoCodeDescriptionValue.setDescription(description);
335                    geoControl.updateGeoCodeDescriptionFromValue(geoCodeDescriptionValue, partyPK);
336                }
337            }
338        }
339    }
340
341}