ContactService validation

This commit is contained in:
akulikov 2023-04-05 14:18:28 +03:00
parent 6ea7520b7b
commit 2f01256a66
6 changed files with 230 additions and 25 deletions

View file

@ -0,0 +1,106 @@
package ru.spcex.clearing.company.config.validation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.profile.Contact;
import ru.clearing.platform.dictionary.ContactTypeDictionary;
import ru.spcex.clearing.company.error.CompanyErrors;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.cud.company.ContactNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.company.ContactUpdateRequest;
import ru.spcex.clearing.validation.common.rules.DictionaryPresentRule;
import ru.spcex.clearing.validation.common.rules.EnumPresentRule;
import ru.spcex.clearing.validation.common.rules.FieldRequiredRule;
import ru.spcex.clearing.validation.common.rules.IdPresentRule;
import ru.spcex.platform.classes.base.SpcexObjectBase;
import ru.spcex.platform.enumeration.ContactTypes;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.validation.ImdgValidationContext;
import ru.spcex.platform.utils.validation.IValidator;
import ru.spcex.platform.utils.validation.ValidatorImpl;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
@Configuration
public class ContactValidationConfig {
@Bean("contactNewRequestValidator")
public Function<ContactNewRequest, IValidator> contactNewRequestValidator(
Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation
) {
return contactNewRequest -> {
ImdgValidationContext<ContactNewRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(contactNewRequest);
Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
addImdg.accept(IMDGDistributedNames.Map_Company);
addImdg.accept(IMDGDistributedNames.Map_ContactTypeDictionary);
return new ValidatorImpl<>(context,
IdPresentRule.instance("companyId",
ContactNewRequest::getCompanyId,
IMDGDistributedNames.Map_Company,
Company.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.CompanyNotFound),
EnumPresentRule.instance("contactType",
ContactNewRequest::getContactType,
ContactTypes.values(),
CompanyErrors.WrongFieldValue,
CompanyErrors.RequiredFieldEmpty),
DictionaryPresentRule.instance("contactType",
ContactNewRequest::getContactType,
IMDGDistributedNames.Map_ContactTypeDictionary,
ContactTypeDictionary.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.WrongFieldValue),
FieldRequiredRule.instance("contactValue",
ContactNewRequest::getContactValue,
CompanyErrors.RequiredFieldEmpty)
);
};
}
@Bean("contactUpdateRequestValidator")
public Function<ContactUpdateRequest, IValidator> contactUpdateRequestValidator(
Map<String, Imdg<? extends SpcexObjectBase>> imdgForValidation
) {
return contactUpdateRequest -> {
ImdgValidationContext<ContactUpdateRequest> context = new ImdgValidationContext<>();
context.setValidatedObject(contactUpdateRequest);
Consumer<String> addImdg = (s) -> context.addImdg(s, imdgForValidation.get(s));
addImdg.accept(IMDGDistributedNames.Map_Contact);
addImdg.accept(IMDGDistributedNames.Map_ContactTypeDictionary);
return new ValidatorImpl<>(context,
IdPresentRule.instance("id",
ContactUpdateRequest::getId,
IMDGDistributedNames.Map_Contact,
Contact.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.CompanyNotFound,
contact -> {
if (contactUpdateRequest.getContactType() == null) return null;
if (!contactUpdateRequest.getContactType().equalsIgnoreCase(contact.getContactType())) {
return CompanyErrors.EditContactType;
}
return null;
}),
EnumPresentRule.instance("contactType",
ContactUpdateRequest::getContactType,
ContactTypes.values(),
false,
CompanyErrors.WrongFieldValue,
CompanyErrors.RequiredFieldEmpty),
DictionaryPresentRule.instance("contactType",
ContactUpdateRequest::getContactType,
IMDGDistributedNames.Map_ContactTypeDictionary,
ContactTypeDictionary.class,
CompanyErrors.RequiredFieldEmpty,
CompanyErrors.WrongFieldValue,
false)
);
};
}
}

View file

@ -4,8 +4,10 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.generated.ClearingMemberCategory;
import ru.clearing.classes.statics.data.profile.Contact;
import ru.clearing.classes.statics.data.profile.ProfileDocument;
import ru.clearing.platform.dictionary.ClearingCategoryDictionary;
import ru.clearing.platform.dictionary.ContactTypeDictionary;
import ru.clearing.platform.dictionary.DocumentTypeDictionary;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.validation.common.ValidationHelper;
@ -31,6 +33,8 @@ public class ValidationConfig {
addImdg.accept(IMDGDistributedNames.Map_ClearingCategoryDictionary, ClearingCategoryDictionary.class);
addImdg.accept(IMDGDistributedNames.Map_ProfileDocument, ProfileDocument.class);
addImdg.accept(IMDGDistributedNames.Map_DocumentTypeDictionary, DocumentTypeDictionary.class);
addImdg.accept(IMDGDistributedNames.Map_ContactTypeDictionary, ContactTypeDictionary.class);
addImdg.accept(IMDGDistributedNames.Map_Contact, Contact.class);
addImdg.accept(IMDGDistributedNames.Map_WorkflowStatusDictionary, DocumentTypeDictionary.class);
addImdg.accept(IMDGDistributedNames.Map_CompanySymbolDictionary, DocumentTypeDictionary.class);

View file

@ -6,44 +6,90 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import ru.clearing.classes.statics.data.profile.Contact;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.clearing.platform.messaging.domain.cud.company.ContactNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.company.ContactUpdateRequest;
import ru.spcex.clearing.platform.messaging.service.QueueConsumer;
import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate;
import ru.spcex.clearing.validation.common.ValidationHelper;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.api.ImdgProvider;
import ru.spcex.platform.utils.validation.IValidator;
import java.util.function.Function;
@Service
public class ContactService extends QueueConsumer implements InitializingBean {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Imdg<Contact> contactMap;
private final ValidationHelper validationHelper;
private final Function<ContactNewRequest, IValidator> contactNewRequestValidator;
private final Function<ContactUpdateRequest, IValidator> contactUpdateRequestValidator;
@Autowired
public ContactService(Consumer<String, Object> kafkaQueue, Producer<String, Object> kafkaProducer,
ImdgProvider imdgProvider) {
public ContactService(Consumer<String, Object> kafkaQueue,
Producer<String, Object> kafkaProducer,
ImdgProvider imdgProvider,
ValidationHelper validationHelper,
@Qualifier("contactNewRequestValidator") Function<ContactNewRequest, IValidator> contactNewRequestValidator,
@Qualifier("contactUpdateRequestValidator") Function<ContactUpdateRequest, IValidator> contactUpdateRequestValidator) {
super(kafkaQueue, kafkaProducer);
this.contactMap = imdgProvider.getImdg(IMDGDistributedNames.Map_Contact, Contact.class);
this.validationHelper = validationHelper;
this.contactNewRequestValidator = contactNewRequestValidator;
this.contactUpdateRequestValidator = contactUpdateRequestValidator;
}
@Override
public void afterPropertiesSet() {
callback(ContactNewRequest.class)
.setConsumer(this::contactNew)
.forDestination(Consts.DESTINATION_CONTACT_NEW, callbacks::put);
callback(ContactUpdateRequest.class)
.setConsumer(this::contactUpdate)
.forDestination(Consts.DESTINATION_CONTACT_UPDATE, callbacks::put);
init();
}
public void contactUpdate(BaseRequest<ContactUpdateRequest> userRequest) {
ContactUpdateRequest req = userRequest.getRequestPayload();
public RequestInfoUpdate contactNew(BaseRequest<ContactNewRequest> userRequest) {
log.debug("ContactNewRequest received");
RequestInfoUpdate requestInfoUpdate = validationHelper.validateTillFirstError(
userRequest, contactNewRequestValidator
);
if (requestInfoUpdate != null) return requestInfoUpdate;
ContactNewRequest contactNewRequest = userRequest.getRequestPayload();
Contact contact = new Contact();
contact.setCompanyId(contactNewRequest.getCompanyId());
contact.setContactType(contactNewRequest.getContactType());
contact.setContactValue(contactNewRequest.getContactValue());
Long id = contactMap.insert(contact);
log.debug("successfully processed, id {}", id);
return null;
}
public RequestInfoUpdate contactUpdate(BaseRequest<ContactUpdateRequest> userRequest) {
log.debug("ContactUpdateRequest received");
RequestInfoUpdate requestInfoUpdate = validationHelper.validateTillFirstError(
userRequest, contactUpdateRequestValidator
);
if (requestInfoUpdate != null) return requestInfoUpdate;
// Тип контакта не меняем, при валидации кидаем ошибку.
ContactUpdateRequest req = userRequest.getRequestPayload();
Contact contact = contactMap.getSingleObjectByID(req.getId());
// contact.setContactType(req.getContactType()); по ТЗ не должен менятся при обновлении
contact.setContactValue(req.getContactValue());
contactMap.update(contact);
log.debug("successfully processed, id {}", contact.getId());
return null;
}
}

View file

@ -67,7 +67,7 @@ class ClearingMemberCategoryServiceTest {
@SpyBean
private MockProducer<String, Object> mockProducer;
private final long COMPANY_ID = 777L;
private long COMPANY_ID;
private Company TEST_COMPANY;
private final String CLEARING_CATEGORY_DICT_CODE = ClearingCategory.B.getKey();
@ -87,9 +87,8 @@ class ClearingMemberCategoryServiceTest {
Imdg<Company> companyImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Company, Company.class);
TEST_COMPANY = new Company();
TEST_COMPANY.setId(COMPANY_ID);
TEST_COMPANY.setWorkflowStatus(WorkflowStatus.Active.getKey());
companyImdg.insert(TEST_COMPANY);
COMPANY_ID = companyImdg.insert(TEST_COMPANY);
clearingCategoryDictionary = new ClearingCategoryDictionary();
clearingCategoryDictionary.setCode(CLEARING_CATEGORY_DICT_CODE);

View file

@ -12,14 +12,22 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import ru.clearing.classes.statics.data.company.Company;
import ru.clearing.classes.statics.data.profile.Contact;
import ru.clearing.platform.dictionary.ContactTypeDictionary;
import ru.spcex.clearing.company.config.BeanConfiguration;
import ru.spcex.clearing.company.config.HazelcastServiceTestConfiguration;
import ru.spcex.clearing.company.config.KafkaConfigTest;
import ru.spcex.clearing.company.config.validation.ContactValidationConfig;
import ru.spcex.clearing.company.config.validation.ValidationConfig;
import ru.spcex.clearing.company.utils.MatcherFactory;
import ru.spcex.clearing.imdg.IMDGDistributedNames;
import ru.spcex.clearing.platform.messaging.domain.BaseRequest;
import ru.spcex.clearing.platform.messaging.domain.Consts;
import ru.spcex.clearing.platform.messaging.domain.cud.company.ContactNewRequest;
import ru.spcex.clearing.platform.messaging.domain.cud.company.ContactUpdateRequest;
import ru.spcex.platform.enumeration.ContactTypes;
import ru.spcex.platform.enumeration.WorkflowStatus;
import ru.spcex.platform.imdg.api.Imdg;
import ru.spcex.platform.imdg.iml.hazelcast.service.HazelcastService;
@ -30,6 +38,9 @@ import static ru.spcex.clearing.company.utils.TestUtils.*;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {
BeanConfiguration.class,
ValidationConfig.class,
ContactValidationConfig.class,
ContactService.class,
KafkaConfigTest.class,
HazelcastServiceTestConfiguration.class})
@ -38,6 +49,7 @@ class ContactServiceTest {
public static final MatcherFactory.Matcher<Contact> CONTACT_MATCHER = usingIgnoringFieldsComparator();
private static final int PARTITION = 0;
private static final String TOPIC_CONTACT_UPDATE = Consts.DESTINATION_CONTACT_UPDATE;
private static final String TOPIC_CONTACT_NEW = Consts.DESTINATION_CONTACT_NEW;
private static final Long ID = 0L;
@Autowired
@ -53,10 +65,50 @@ class ContactServiceTest {
@SpyBean
private MockProducer<String, Object> mockProducer;
private Company TEST_COMPANY;
private Long COMPANY_ID;
@PostConstruct
private void init() {
hazelcastServiceTest.waitAvailable();
contactImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Contact, Contact.class);
Imdg<Company> companyImdg = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Company, Company.class);
TEST_COMPANY = new Company();
TEST_COMPANY.setWorkflowStatus(WorkflowStatus.Active.getKey());
COMPANY_ID = companyImdg.insert(TEST_COMPANY);
ContactTypeDictionary contactTypeDictionary = new ContactTypeDictionary();
contactTypeDictionary.setCode(ContactTypes.adrs.getKey());
contactTypeDictionary.setName("name");
Imdg<ContactTypeDictionary> contactTypeDictionaryImdg = hazelcastServiceTest.getImdg(
IMDGDistributedNames.Map_ContactTypeDictionary, ContactTypeDictionary.class
);
contactTypeDictionaryImdg.insert(contactTypeDictionary);
}
@Test
void contactNew() throws InterruptedException {
//ARRANGE
ContactNewRequest contactNewRequest = new ContactNewRequest();
contactNewRequest.setCompanyId(COMPANY_ID);
contactNewRequest.setContactType(ContactTypes.adrs.getKey());
contactNewRequest.setContactValue("value");
Contact predictableContact = new Contact();
predictableContact.setCompanyId(COMPANY_ID);
predictableContact.setContactType(ContactTypes.adrs.getKey());
predictableContact.setContactValue("value");
//ACT
String jsonString = getJsonStringForNew(contactNewRequest, ID);
addRecordToKafka((MockConsumer) contactService.getConsumer(), TOPIC_CONTACT_NEW, PARTITION, 0, jsonString);
//ASSERT
waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord);
Contact resultNew = contactImdg.getAllValues().iterator().next();
predictableContact.setId(resultNew.getId());
CONTACT_MATCHER.assertMatch(resultNew, predictableContact);
}
/**
@ -65,39 +117,38 @@ class ContactServiceTest {
* Входной запрос {@link ContactUpdateRequest}:<br>
* {@link ContactUpdateRequest#id} - Идентификатор записи<br>
* {@link ContactUpdateRequest#companyId} - Идентификатор записи<br>
* {@link ContactUpdateRequest#contactType} - 1234<br>
* {@link ContactUpdateRequest#contactType} - ADDR<br>
* {@link ContactUpdateRequest#contactValue} - new ContactValue<br>
*/
@Test
void contactUpdate() throws InterruptedException {
//ARRANGE
Long existContactID;
Contact existsContact = new Contact();
existsContact.setId(ID);
existsContact.setCompanyId(ID);
existsContact.setContactType("0000");
existsContact.setCompanyId(COMPANY_ID);
existsContact.setContactType(ContactTypes.adrs.getKey());
existsContact.setContactValue("exists ContactValue");
contactImdg.insert(existsContact);
existContactID = contactImdg.insert(existsContact);
ContactUpdateRequest contactUpdateRequest = new ContactUpdateRequest();
contactUpdateRequest.setId(ID);
contactUpdateRequest.setCompanyId(1L);
contactUpdateRequest.setContactType("1234");
contactUpdateRequest.setId(existContactID);
contactUpdateRequest.setContactType(ContactTypes.adrs.getKey());
contactUpdateRequest.setContactValue("new ContactValue");
Contact predictableContact = new Contact();
predictableContact.setId(ID);
predictableContact.setCompanyId(ID);
predictableContact.setContactType("0000");
predictableContact.setId(existContactID);
predictableContact.setCompanyId(COMPANY_ID);
predictableContact.setContactType(ContactTypes.adrs.getKey());
predictableContact.setContactValue("new ContactValue");
//ACT
String jsonString = getJsonStringForUPDATE(contactUpdateRequest, ID);
String jsonString = getJsonStringForUPDATE(contactUpdateRequest, existContactID);
addRecordToKafka((MockConsumer) contactService.getConsumer(), TOPIC_CONTACT_UPDATE, PARTITION, 0, jsonString);
//ASSERT
waitingWhenAddedRecordAndCheckIt(ID, mockProducer, producerRecord);
waitingWhenAddedRecordAndCheckIt(existContactID, mockProducer, producerRecord);
Contact resultUpdating = contactImdg.getSingleObjectByID(ID);
Contact resultUpdating = contactImdg.getSingleObjectByID(existContactID);
CONTACT_MATCHER.assertMatch(resultUpdating, predictableContact);
}
}

View file

@ -68,7 +68,7 @@ class ProfileDocumentServiceTest {
@SpyBean
private MockProducer<String, Object> mockProducer;
private final long COMPANY_ID = 777L;
private long COMPANY_ID;
private Company TEST_COMPANY;
private DocumentTypes TEST_DOCUMENT_TYPE = DocumentTypes.cio;
@ -86,9 +86,8 @@ class ProfileDocumentServiceTest {
this.companyMap = hazelcastServiceTest.getImdg(IMDGDistributedNames.Map_Company, Company.class);
TEST_COMPANY = new Company();
TEST_COMPANY.setId(COMPANY_ID);
TEST_COMPANY.setWorkflowStatus(WorkflowStatus.Active.getKey());
companyMap.insert(TEST_COMPANY);
COMPANY_ID = companyMap.insert(TEST_COMPANY);
Imdg<DocumentTypeDictionary> documentTypeDictionaryImdg = hazelcastServiceTest.getImdg(
IMDGDistributedNames.Map_DocumentTypeDictionary,