From 8bad51956a05d5e780bd579faddd2489d5122afb Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Wed, 30 Dec 2020 00:49:10 +0300 Subject: [PATCH 01/30] TgbotController: Refactoring --- .../receipt/rest/controller/TgbotController.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/rest-api/src/main/java/space/shefer/receipt/rest/controller/TgbotController.java b/rest-api/src/main/java/space/shefer/receipt/rest/controller/TgbotController.java index ef5824b..8aba871 100644 --- a/rest-api/src/main/java/space/shefer/receipt/rest/controller/TgbotController.java +++ b/rest-api/src/main/java/space/shefer/receipt/rest/controller/TgbotController.java @@ -5,7 +5,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.RequiredArgsConstructor; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -20,15 +20,11 @@ @Tag(name = "Telegram bot") @RestController @RequestMapping("tgbot") +@RequiredArgsConstructor public class TgbotController { private final FnsReceiptService receiptService; - @Autowired - public TgbotController(FnsReceiptService receiptService) { - this.receiptService = receiptService; - } - @Operation( description = "Submit receipt from telegram-bot", responses = @ApiResponse( @@ -45,8 +41,7 @@ public String create(@RequestBody TgbotCreateBody body) { FnsAppReceiptDto fnsAppReceiptDto = FnsAppReceiptDto.fromString(body.getReceiptJson()); return receiptService .update(fnsAppReceiptDto, new Receipt(), ReceiptProvider.TGBOT_NALOG.name()) - .getId() - .toString(); + .getId(); } } From 9b1d293d60d7c37b3fa6d2f124a912e9cdea1c78 Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Wed, 30 Dec 2020 00:49:32 +0300 Subject: [PATCH 02/30] Delete UserController --- .../rest/controller/UserController.java | 49 ------------------- 1 file changed, 49 deletions(-) delete mode 100644 rest-api/src/main/java/space/shefer/receipt/rest/controller/UserController.java diff --git a/rest-api/src/main/java/space/shefer/receipt/rest/controller/UserController.java b/rest-api/src/main/java/space/shefer/receipt/rest/controller/UserController.java deleted file mode 100644 index 424c786..0000000 --- a/rest-api/src/main/java/space/shefer/receipt/rest/controller/UserController.java +++ /dev/null @@ -1,49 +0,0 @@ -package space.shefer.receipt.rest.controller; - -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; -import space.shefer.receipt.fnssdk.webclient.FnsReceiptWebClient; -import space.shefer.receipt.platform.core.entity.UserProfile; -import space.shefer.receipt.platform.core.service.UserProfileService; -import space.shefer.receipt.rest.dto.UserLoginDto; -import space.shefer.receipt.rest.dto.UserPasswordRestoreDto; -import space.shefer.receipt.rest.dto.UserSignUpDto; - - -@Tag(name = "Users") -@RestController -public class UserController { - - private final FnsReceiptWebClient fnsReceiptWebClient; - private final UserProfileService userProfileService; - - @Autowired - public UserController(FnsReceiptWebClient fnsReceiptWebClient, UserProfileService userProfileService) { - this.fnsReceiptWebClient = fnsReceiptWebClient; - this.userProfileService = userProfileService; - } - - @RequestMapping(value = "/login", method = RequestMethod.POST, produces = MediaType.TEXT_PLAIN_VALUE) - public String login(@RequestBody UserLoginDto userLoginDto) { - fnsReceiptWebClient.login(userLoginDto.getPhone(), userLoginDto.getPassword()); - UserProfile userProfile = userProfileService.createOrUpdate(userLoginDto.getPhone(), userLoginDto.getPassword()); - return userProfile.getAccessToken(); - } - - @RequestMapping(value = "/signUp", method = RequestMethod.POST) - public void signUp(@RequestBody UserSignUpDto userSignUpDto) { - fnsReceiptWebClient.signUp(userSignUpDto.getEmail(), userSignUpDto.getName(), userSignUpDto.getPhone()); - } - - @RequestMapping(value = "/passwordRestore", method = RequestMethod.POST) - public void passwordRestore(@RequestBody UserPasswordRestoreDto userPasswordRestoreDto) { - fnsReceiptWebClient.passwordRestore(userPasswordRestoreDto.getPhone()); - } - - -} From 543ebeabb7cc09bead14b44c35e6eeceeced497a Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Sun, 10 Jan 2021 13:29:32 +0300 Subject: [PATCH 03/30] Entities: Set Hibernate naming strategy --- .../platform/core/entity/BaseUuidIdEntity.java | 4 ---- .../receipt/platform/core/entity/Receipt.java | 13 +------------ core/src/main/resources/application.properties | 2 ++ 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/space/shefer/receipt/platform/core/entity/BaseUuidIdEntity.java b/core/src/main/java/space/shefer/receipt/platform/core/entity/BaseUuidIdEntity.java index 3542f78..0e2aaee 100644 --- a/core/src/main/java/space/shefer/receipt/platform/core/entity/BaseUuidIdEntity.java +++ b/core/src/main/java/space/shefer/receipt/platform/core/entity/BaseUuidIdEntity.java @@ -7,7 +7,6 @@ import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import javax.persistence.Column; import javax.persistence.EntityListeners; import javax.persistence.GeneratedValue; import javax.persistence.Id; @@ -23,15 +22,12 @@ public class BaseUuidIdEntity { @Id @GeneratedValue(generator = "uuid") @GenericGenerator(name = "uuid", strategy = "uuid2") - @Column(name = "id", unique = true) protected String id; @CreatedDate - @Column(name = "created_at", nullable = false) protected LocalDateTime createdAt; @LastModifiedDate - @Column(name = "updated_at", nullable = true) protected LocalDateTime updatedAt; } diff --git a/core/src/main/java/space/shefer/receipt/platform/core/entity/Receipt.java b/core/src/main/java/space/shefer/receipt/platform/core/entity/Receipt.java index dcb7e65..c0cd2f0 100644 --- a/core/src/main/java/space/shefer/receipt/platform/core/entity/Receipt.java +++ b/core/src/main/java/space/shefer/receipt/platform/core/entity/Receipt.java @@ -28,27 +28,20 @@ @NoArgsConstructor public class Receipt extends BaseUuidIdEntity { - @Column(name = "date", nullable = false) private LocalDateTime date; - @Column(name = "fn", nullable = false) private String fn; - @Column(name = "fd", nullable = false) private String fd; - @Column(name = "fp", nullable = false) private String fp; - @Column(name = "sum", nullable = false) private Double sum; @Nullable - @Column(name = "provider") private String provider; @Enumerated(EnumType.STRING) - @Column(name = "status", nullable = false) private ReceiptStatus status; @Builder.Default @@ -57,23 +50,19 @@ public class Receipt extends BaseUuidIdEntity { private List items = new ArrayList<>(); @Nullable - @Column(name = "merchant_name") private String merchantName; @Nullable - @Column(name = "merchant_inn") private String merchantInn; @Nullable - @Column(name = "merchant_place_address") private String merchantPlaceAddress; @Nullable @ManyToOne @JoinColumn(name = "user_profile_id") private UserProfile userProfile; - - @Column(name = "load_attempts", nullable = false, columnDefinition = "INT DEFAULT 0") + private long loadAttempts; } diff --git a/core/src/main/resources/application.properties b/core/src/main/resources/application.properties index 1b1289e..a1b55a5 100644 --- a/core/src/main/resources/application.properties +++ b/core/src/main/resources/application.properties @@ -5,6 +5,8 @@ spring.datasource.password= # The SQL dialect makes Hibernate generate better SQL for the chosen database spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect +spring.jpa.properties.psysical_naming_strategy=com.vladmihalcea.hibernate.type.util.CamelCaseToSnakeCaseNamingStrategy + # Hibernate ddl auto (create, create-drop, validate, update) spring.jpa.hibernate.ddl-auto=update From c1d5f0a731115e88d3d81e0f301dd674e5b32914 Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Sun, 10 Jan 2021 13:31:08 +0300 Subject: [PATCH 04/30] Fix compilation errors in tests because of new BaseUuidIdEntity --- .../receipt/platform/core/entity/Item.java | 16 ++++--- .../receipt/platform/core/entity/Receipt.java | 15 ++++--- .../repository/ItemRepositorySlowTest.java | 28 ++++++------ .../repository/ReceiptRepositorySlowTest.java | 44 +++++++++---------- .../rest/controller/TgbotControllerTest.java | 6 ++- .../rest/service/ReceiptServiceTest.java | 12 +++-- 6 files changed, 70 insertions(+), 51 deletions(-) diff --git a/core/src/main/java/space/shefer/receipt/platform/core/entity/Item.java b/core/src/main/java/space/shefer/receipt/platform/core/entity/Item.java index 249a7c0..11d595b 100644 --- a/core/src/main/java/space/shefer/receipt/platform/core/entity/Item.java +++ b/core/src/main/java/space/shefer/receipt/platform/core/entity/Item.java @@ -1,20 +1,26 @@ package space.shefer.receipt.platform.core.entity; import lombok.AllArgsConstructor; -import lombok.Data; +import lombok.Builder; +import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; -@Entity -@Table(name = "item") -@Data @AllArgsConstructor +@Entity +@Getter @NoArgsConstructor -public class Item extends BaseUuidIdEntity{ +@Setter +@Builder +@Table(name = "item") +@ToString +public class Item extends BaseUuidIdEntity { private String text; diff --git a/core/src/main/java/space/shefer/receipt/platform/core/entity/Receipt.java b/core/src/main/java/space/shefer/receipt/platform/core/entity/Receipt.java index c0cd2f0..c30b8d2 100644 --- a/core/src/main/java/space/shefer/receipt/platform/core/entity/Receipt.java +++ b/core/src/main/java/space/shefer/receipt/platform/core/entity/Receipt.java @@ -2,12 +2,13 @@ import lombok.AllArgsConstructor; import lombok.Builder; -import lombok.Data; +import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; import space.shefer.receipt.platform.core.dto.ReceiptStatus; import javax.annotation.Nullable; -import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; @@ -20,12 +21,14 @@ import java.util.ArrayList; import java.util.List; -@Entity -@Table(name = "receipt") -@Data -@Builder @AllArgsConstructor +@Builder +@Entity +@Getter @NoArgsConstructor +@Setter +@Table(name = "receipt") +@ToString public class Receipt extends BaseUuidIdEntity { private LocalDateTime date; diff --git a/core/src/test/java/space/shefer/receipt/platform/core/repository/ItemRepositorySlowTest.java b/core/src/test/java/space/shefer/receipt/platform/core/repository/ItemRepositorySlowTest.java index 37d3e6d..1d2c4a0 100644 --- a/core/src/test/java/space/shefer/receipt/platform/core/repository/ItemRepositorySlowTest.java +++ b/core/src/test/java/space/shefer/receipt/platform/core/repository/ItemRepositorySlowTest.java @@ -29,10 +29,10 @@ public class ItemRepositorySlowTest { @Test public void getItems_defaultFilter() { List itemsInitial = asList( - new Item(null, "text1", 1001.0, 101.0, null), - new Item(null, "text2", 1002.0, 102.0, null), - new Item(null, "text3", 1003.0, 103.0, null), - new Item(null, "text4", 1004.0, 104.0, null) + new Item("text1", 1001.0, 101.0, null), + new Item("text2", 1002.0, 102.0, null), + new Item("text3", 1003.0, 103.0, null), + new Item("text4", 1004.0, 104.0, null) ); repository.saveAll(itemsInitial); List itemsAll = repository.findAll(); @@ -56,19 +56,19 @@ public void getItems_fullFilter() { double priceMax = priceOk + 5; double priceMin = priceOk - 5; // OK - repository.save(new Item(null, "text1", priceOk, 101.0, receiptOk)); + repository.save(new Item("text1", priceOk, 101.0, receiptOk)); // OK - repository.save(new Item(null, "text1", priceMin, 101.0, receiptOk)); + repository.save(new Item("text1", priceMin, 101.0, receiptOk)); // OK - repository.save(new Item(null, "text1", priceMax, 101.0, receiptOk)); + repository.save(new Item("text1", priceMax, 101.0, receiptOk)); // Wrong text - repository.save(new Item(null, "text2", priceOk, 101.0, receiptOk)); + repository.save(new Item("text2", priceOk, 101.0, receiptOk)); // Wrong receipt - repository.save(new Item(null, "text1", priceOk, 101.0, null)); + repository.save(new Item("text1", priceOk, 101.0, null)); // Price less than minimal - repository.save(new Item(null, "text1", priceMin - 1, 101.0, receiptOk)); + repository.save(new Item("text1", priceMin - 1, 101.0, receiptOk)); // Price greater than maximal - repository.save(new Item(null, "text1", priceMax + 1, 101.0, receiptOk)); + repository.save(new Item("text1", priceMax + 1, 101.0, receiptOk)); { ReportItemFilter filter = new ReportItemFilter(); filter.setReceiptIds(asList(receiptOk.getId())); @@ -77,9 +77,9 @@ public void getItems_fullFilter() { filter.setTextEquals("text1"); List actual = repository.getItems(filter); assertEquals(3, actual.size()); - assertSimilar(new Item(null, "text1", priceOk, 101.0, receiptOk), actual.get(0)); - assertSimilar(new Item(null, "text1", priceMin, 101.0, receiptOk), actual.get(1)); - assertSimilar(new Item(null, "text1", priceMax, 101.0, receiptOk), actual.get(2)); + assertSimilar(new Item("text1", priceOk, 101.0, receiptOk), actual.get(0)); + assertSimilar(new Item("text1", priceMin, 101.0, receiptOk), actual.get(1)); + assertSimilar(new Item("text1", priceMax, 101.0, receiptOk), actual.get(2)); } } diff --git a/core/src/test/java/space/shefer/receipt/platform/core/repository/ReceiptRepositorySlowTest.java b/core/src/test/java/space/shefer/receipt/platform/core/repository/ReceiptRepositorySlowTest.java index 04de9ad..5c0e2cc 100644 --- a/core/src/test/java/space/shefer/receipt/platform/core/repository/ReceiptRepositorySlowTest.java +++ b/core/src/test/java/space/shefer/receipt/platform/core/repository/ReceiptRepositorySlowTest.java @@ -43,13 +43,13 @@ public void getReceipts_noFilter() { String merchantPlaceAddress = "197374, СПб, ул. Савушкина, 112, лит. А"; UserProfile userProfile = userProfileRepository.save(createTestUser()); List receiptsInitial = Arrays.asList( - new Receipt(null, date, "83479", "96253", "76193", 123.45, "TAXCOM", LOADED, + new Receipt(date, "83479", "96253", "76193", 123.45, "TAXCOM", LOADED, emptyList(), merchantName, merchantInn, merchantPlaceAddress, userProfile, loadAttempts), - new Receipt(null, date, "34780", "89255", "82661", 121.44, "TAXCOM", LOADED, + new Receipt(date, "34780", "89255", "82661", 121.44, "TAXCOM", LOADED, emptyList(), merchantName, merchantInn, merchantPlaceAddress, userProfile, loadAttempts), - new Receipt(null, date, "03845", "11111", "11547", 723.75, "TAXCOM", LOADED, + new Receipt(date, "03845", "11111", "11547", 723.75, "TAXCOM", LOADED, emptyList(), merchantName, merchantInn, merchantPlaceAddress, userProfile, loadAttempts), - new Receipt(null, date, "82640", "34579", "99999", 103.55, "TAXCOM", LOADED, + new Receipt(date, "82640", "34579", "99999", 103.55, "TAXCOM", LOADED, emptyList(), merchantName, merchantInn, merchantPlaceAddress, userProfile, loadAttempts) ); repository.saveAll(receiptsInitial); @@ -82,94 +82,94 @@ public void getReceipt_fullFilter() { String merchantName = "ООО \"Лента\""; String merchantInn = "7814148471"; String merchantPlaceAddress = "197374, СПб, ул. Савушкина, 112, лит. А"; - Long bannedId; + String bannedId; List expectedReceipts = new ArrayList<>(); {// WRONG ID Receipt receipt = - repository.save(new Receipt(null, + repository.save(new Receipt( dateOk, "11111", "22222", "33333", sumOk, "TAXCOM", LOADED, emptyList(), merchantName, merchantInn, merchantPlaceAddress, userProfile, loadAttempts)); bannedId = receipt.getId(); } {// OK Receipt receipt = - repository.save(new Receipt(null, + repository.save(new Receipt( dateOk, "11111", "22222", "33333", sumOk, "TAXCOM", LOADED, emptyList(), merchantName, merchantInn, merchantPlaceAddress, userProfile, loadAttempts)); expectedReceipts.add(receipt); } {// OK Receipt receipt = - repository.save(new Receipt(null, + repository.save(new Receipt( dateOk, "11111", "22222", "33333", sumOk, "TAXCOM", LOADED, emptyList(), merchantName, merchantInn, merchantPlaceAddress, userProfile, loadAttempts)); expectedReceipts.add(receipt); } {// WRONG DATE: WRONG YEAR - repository.save(new Receipt(null, + repository.save(new Receipt( dateWrongYear, "11111", "22222", "33333", sumOk, "TAXCOM", LOADED, emptyList(), merchantName, merchantInn, merchantPlaceAddress, userProfile, loadAttempts)); } {// WRONG DATE: WRONG MONTH - repository.save(new Receipt(null, + repository.save(new Receipt( dateWrongMonth, "11111", "22222", "33333", sumOk, "TAXCOM", LOADED, emptyList(), merchantName, merchantInn, merchantPlaceAddress, userProfile, loadAttempts)); } {// WRONG DATE: WRONG DATE - repository.save(new Receipt(null, + repository.save(new Receipt( dateWrongDate, "11111", "22222", "33333", sumOk, "TAXCOM", LOADED, emptyList(), merchantName, merchantInn, merchantPlaceAddress, userProfile, loadAttempts)); } {// WRONG DATE: WRONG HOUR - repository.save(new Receipt(null, + repository.save(new Receipt( dateWrongHour, "11111", "22222", "33333", sumOk, "TAXCOM", LOADED, emptyList(), merchantName, merchantInn, merchantPlaceAddress, userProfile, loadAttempts)); } {// WRONG DATE: WRONG MINUTE - repository.save(new Receipt(null, + repository.save(new Receipt( dateWrongMinute, "11111", "22222", "33333", sumOk, "TAXCOM", LOADED, emptyList(), merchantName, merchantInn, merchantPlaceAddress, userProfile, loadAttempts)); } {// WRONG DATE: WRONG SECOND - repository.save(new Receipt(null, + repository.save(new Receipt( dateWrongSecond, "11111", "22222", "33333", sumOk, "TAXCOM", LOADED, emptyList(), merchantName, merchantInn, merchantPlaceAddress, userProfile, loadAttempts)); } {// WRONG FN - repository.save(new Receipt(null, + repository.save(new Receipt( dateOk, "83759", "22222", "33333", sumOk, "TAXCOM", LOADED, emptyList(), merchantName, merchantInn, merchantPlaceAddress, userProfile, loadAttempts)); } {// WRONG FD - repository.save(new Receipt(null, + repository.save(new Receipt( dateOk, "11111", "02349", "33333", sumOk, "TAXCOM", LOADED, emptyList(), merchantName, merchantInn, merchantPlaceAddress, userProfile, loadAttempts)); } {// WRONG FP - repository.save(new Receipt(null, + repository.save(new Receipt( dateOk, "11111", "22222", "73458", sumOk, "TAXCOM", LOADED, emptyList(), merchantName, merchantInn, merchantPlaceAddress, userProfile, loadAttempts)); } {// WRONG SUM - repository.save(new Receipt(null, + repository.save(new Receipt( dateOk, "11111", "22222", "33333", 65.3, "TAXCOM", LOADED, emptyList(), merchantName, merchantInn, merchantPlaceAddress, userProfile, loadAttempts)); } {// WRONG STATUS - repository.save(new Receipt(null, + repository.save(new Receipt( dateOk, "11111", "22222", "33333", sumOk, "TAXCOM", IDLE, emptyList(), merchantName, merchantInn, merchantPlaceAddress, userProfile, loadAttempts)); } {// WRONG MERCHANT NAME - repository.save(new Receipt(null, + repository.save(new Receipt( dateOk, "11111", "22222", "33333", sumOk, "TAXCOM", LOADED, emptyList(), "dummy", merchantInn, merchantPlaceAddress, userProfile, loadAttempts)); } repository.flush(); - Long finalBannedId = bannedId; - List allowedIds = repository.findAll().stream().map(Receipt::getId) + String finalBannedId = bannedId; + List allowedIds = repository.findAll().stream().map(Receipt::getId) .filter(it -> !Objects.equals(it, finalBannedId)).collect(Collectors.toList()); { diff --git a/rest-api/src/test/java/space/shefer/receipt/rest/controller/TgbotControllerTest.java b/rest-api/src/test/java/space/shefer/receipt/rest/controller/TgbotControllerTest.java index 7768f09..5ed6747 100644 --- a/rest-api/src/test/java/space/shefer/receipt/rest/controller/TgbotControllerTest.java +++ b/rest-api/src/test/java/space/shefer/receipt/rest/controller/TgbotControllerTest.java @@ -49,7 +49,11 @@ public void testReceipts() throws Exception { body.setReceiptJson(receiptJson); String bodyString = new ObjectMapper().writeValueAsString(body); - doAnswer(__ -> Receipt.builder().id(807L).build()).when(service).update(any(), any(), anyString()); + doAnswer(__ -> { + Receipt receipt = new Receipt(); + receipt.setId("807"); + return receipt; + }).when(service).update(any(), any(), anyString()); mockMvc .perform(post("/tgbot/create") diff --git a/rest-api/src/test/java/space/shefer/receipt/rest/service/ReceiptServiceTest.java b/rest-api/src/test/java/space/shefer/receipt/rest/service/ReceiptServiceTest.java index 070e294..ee7a1de 100644 --- a/rest-api/src/test/java/space/shefer/receipt/rest/service/ReceiptServiceTest.java +++ b/rest-api/src/test/java/space/shefer/receipt/rest/service/ReceiptServiceTest.java @@ -44,8 +44,8 @@ public void getReceipts() { metaFilter.setSumMax(800.0); when(receiptRepository.getReceipts(any())) .thenReturn(Arrays.asList( - Receipt.builder().id(1L).build(), - Receipt.builder().id(2L).build() + createReceiptWithId("1"), + createReceiptWithId("2") )); service.getReceipts(metaFilter); verify(receiptRepository).getReceipts(metaFilter); @@ -64,7 +64,7 @@ public void create() { receipt.setFd("2222"); receipt.setFp("3333"); receipt.setSum(100.0); - when(receiptRepository.save(any())).thenReturn(Receipt.builder().id(400L).build()); + when(receiptRepository.save(any())).thenReturn(createReceiptWithId("400")); service.create(receipt, userProfile); ArgumentCaptor receiptCaptor = ArgumentCaptor.forClass(Receipt.class); verify(receiptRepository).save(receiptCaptor.capture()); @@ -88,4 +88,10 @@ public void trimAddressLine() { assertEquals(ReceiptService.trimAddressLine("----!#@#$!____--"), ""); } + private Receipt createReceiptWithId(String id){ + Receipt receipt = new Receipt(); + receipt.setId(id); + return receipt; + } + } From 4bb80161f16f7ac725958c9c3db9383316c4f241 Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Sun, 10 Jan 2021 13:31:35 +0300 Subject: [PATCH 05/30] FnsApiReceiptDto: Remove redundant annotation --- .../kotlin/space/shefer/receipt/fnssdk/dto/FnsApiReceiptDto.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/dto/FnsApiReceiptDto.kt b/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/dto/FnsApiReceiptDto.kt index 556fbc2..9b58aa3 100644 --- a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/dto/FnsApiReceiptDto.kt +++ b/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/dto/FnsApiReceiptDto.kt @@ -2,12 +2,10 @@ package space.shefer.receipt.fnssdk.dto import com.fasterxml.jackson.annotation.JsonFormat import com.fasterxml.jackson.annotation.JsonIgnoreProperties -import com.fasterxml.jackson.annotation.JsonInclude import java.time.LocalDateTime @JsonIgnoreProperties(ignoreUnknown = true) class FnsApiReceiptDto : FnsReceiptDto() { @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "utc") - @JsonInclude(JsonInclude.Include.ALWAYS) override var dateTime: LocalDateTime? = null } From 394020d2143ca1ed7506ddb186d4aae3ba18a2be Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Sun, 10 Jan 2021 13:33:05 +0300 Subject: [PATCH 06/30] Fix compilation errors in DTOS because of new BaseUuidIdEntity --- .../shefer/receipt/platform/core/dto/ReportItemFilter.java | 2 +- .../shefer/receipt/platform/core/dto/ReportMetaFilter.java | 2 +- .../java/space/shefer/receipt/rest/dto/ReceiptItemDto.java | 2 +- .../java/space/shefer/receipt/rest/dto/ReceiptMetaDto.java | 5 ++--- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/core-dto/src/main/java/space/shefer/receipt/platform/core/dto/ReportItemFilter.java b/core-dto/src/main/java/space/shefer/receipt/platform/core/dto/ReportItemFilter.java index a9a91ce..21b4e84 100644 --- a/core-dto/src/main/java/space/shefer/receipt/platform/core/dto/ReportItemFilter.java +++ b/core-dto/src/main/java/space/shefer/receipt/platform/core/dto/ReportItemFilter.java @@ -14,7 +14,7 @@ @Builder(toBuilder = true) public class ReportItemFilter { @Nullable - private List receiptIds; + private List receiptIds; @Nullable private Double minPrice; @Nullable diff --git a/core-dto/src/main/java/space/shefer/receipt/platform/core/dto/ReportMetaFilter.java b/core-dto/src/main/java/space/shefer/receipt/platform/core/dto/ReportMetaFilter.java index b25dbfc..9558836 100644 --- a/core-dto/src/main/java/space/shefer/receipt/platform/core/dto/ReportMetaFilter.java +++ b/core-dto/src/main/java/space/shefer/receipt/platform/core/dto/ReportMetaFilter.java @@ -20,7 +20,7 @@ public class ReportMetaFilter { @Nullable - List ids; + List ids; @Schema( description = DateUtil.RECEIPT_DATETIME_DESCRIPTION, diff --git a/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/ReceiptItemDto.java b/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/ReceiptItemDto.java index e6afe44..2487cae 100644 --- a/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/ReceiptItemDto.java +++ b/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/ReceiptItemDto.java @@ -4,7 +4,7 @@ @Data public class ReceiptItemDto { - private Long receiptId; + private String receiptId; private String text; private Double price; private Double amount; diff --git a/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/ReceiptMetaDto.java b/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/ReceiptMetaDto.java index 5b383d8..5297b6d 100644 --- a/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/ReceiptMetaDto.java +++ b/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/ReceiptMetaDto.java @@ -14,11 +14,10 @@ public class ReceiptMetaDto { @Schema( title = "Receipt identifier", - minimum = "0", required = true, - example = "135" + example = "saf-asdfb-43c54-sad" ) - private Long id; + private String id; @Schema( required = true, From a17b6823b18c237e37b3dff6a08434d0a07c9c3e Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Sat, 30 Jan 2021 19:37:43 +0300 Subject: [PATCH 07/30] Module 'storage-filesystem' --- storage-filesystem/README.md | 6 ++++++ storage-filesystem/build.gradle | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 storage-filesystem/README.md create mode 100644 storage-filesystem/build.gradle diff --git a/storage-filesystem/README.md b/storage-filesystem/README.md new file mode 100644 index 0000000..d643516 --- /dev/null +++ b/storage-filesystem/README.md @@ -0,0 +1,6 @@ +# storage-filesystem + +Allows to store receipt data in a single directory in a filesystem. + +Allows to copy/share/backup data with ease. + diff --git a/storage-filesystem/build.gradle b/storage-filesystem/build.gradle new file mode 100644 index 0000000..5552fa2 --- /dev/null +++ b/storage-filesystem/build.gradle @@ -0,0 +1,23 @@ +plugins { + id "io.freefair.lombok" + id 'org.springframework.boot' +} + +dependencies { + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-csv' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' + implementation 'com.google.code.findbugs:jsr305' + implementation 'commons-codec:commons-codec' + implementation 'org.apache.commons:commons-lang3' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-actuator' + implementation 'org.springframework:spring-context-support' + implementation 'org.projectlombok:lombok' + implementation 'org.springdoc:springdoc-openapi-ui' + + testImplementation project(':test-util') + + testImplementation "com.h2database:h2" + testImplementation "org.springframework.boot:spring-boot-starter-test" +} From 7051400aeab1130de29465c149c5b64dc0f57341 Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Sat, 30 Jan 2021 19:31:57 +0300 Subject: [PATCH 08/30] Create filesystem dao --- .../space/shefer/receipt/storages/Dao.java | 15 +++ .../storages/filesystem/FileSystemDao.java | 100 ++++++++++++++++++ .../storages/filesystem/FileUtils.java | 68 ++++++++++++ .../storages/filesystem/FormatType.java | 6 ++ 4 files changed, 189 insertions(+) create mode 100644 storage-filesystem/src/main/java/space/shefer/receipt/storages/Dao.java create mode 100644 storage-filesystem/src/main/java/space/shefer/receipt/storages/filesystem/FileSystemDao.java create mode 100644 storage-filesystem/src/main/java/space/shefer/receipt/storages/filesystem/FileUtils.java create mode 100644 storage-filesystem/src/main/java/space/shefer/receipt/storages/filesystem/FormatType.java diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/storages/Dao.java b/storage-filesystem/src/main/java/space/shefer/receipt/storages/Dao.java new file mode 100644 index 0000000..276e198 --- /dev/null +++ b/storage-filesystem/src/main/java/space/shefer/receipt/storages/Dao.java @@ -0,0 +1,15 @@ +package space.shefer.receipt.storages; + +import javax.annotation.Nullable; +import java.util.List; + +public interface Dao { + + T save(String id, T entity); + T getById(String id); + @Nullable + T getByIdOrNull(String id); + List getAll(); + void delete(String id); + +} diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/storages/filesystem/FileSystemDao.java b/storage-filesystem/src/main/java/space/shefer/receipt/storages/filesystem/FileSystemDao.java new file mode 100644 index 0000000..10e91ed --- /dev/null +++ b/storage-filesystem/src/main/java/space/shefer/receipt/storages/filesystem/FileSystemDao.java @@ -0,0 +1,100 @@ +package space.shefer.receipt.storages.filesystem; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import space.shefer.receipt.storages.Dao; + +import javax.annotation.Nullable; +import java.io.File; +import java.io.FileWriter; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.stream.Collectors; + +import static space.shefer.receipt.storages.filesystem.FileUtils.*; + +@RequiredArgsConstructor +public class FileSystemDao implements Dao { + + private final String rootPath; + private final String subPath; + private final FormatType defaultFormatType; + private final Class entityType; + + private static final ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()) + .findAndRegisterModules() + .enable(SerializationFeature.INDENT_OUTPUT); + + @Override + @SneakyThrows + public T save(String id, T entity) { + String serialized = serialize(entity); + + deleteFileIfExists(getFilePath(id)); + + File entityFile = createEmptyFile(getFilePath(id)); + + try (FileWriter myWriter = new FileWriter(entityFile)) { + myWriter.write(serialized); + myWriter.flush(); + } + + return entity; + } + + @Override + public void delete(String id) { + deleteFileIfExists(getFilePath(id)); + } + + @SneakyThrows + @Override + public T getById(String id) { + String fileContents = readFileOrNull(getFilePath(id)); + + if (fileContents == null) { + throw new NoSuchElementException("No entoty for id " + id); + } + + return objectMapper.readValue(fileContents, entityType); + } + + @SneakyThrows + @Nullable + @Override + public T getByIdOrNull(String id) { + String fileContents = readFileOrNull(getFilePath(id)); + + if (fileContents == null) { + return null; + } + + return objectMapper.readValue(fileContents, entityType); + } + + @Override + public List getAll() { + List fileNamesOfDirectory = getFileNamesOfDirectory(getDirectoryPath()); + + return fileNamesOfDirectory.stream() + .map(this::getById) + .collect(Collectors.toList()); + } + + private String serialize(T entity) throws JsonProcessingException { + return objectMapper.writeValueAsString(entity); + } + + private String getFilePath(String id) { + return getDirectoryPath() + File.separator + id + "." + defaultFormatType.name().toLowerCase(); + } + + private String getDirectoryPath() { + return rootPath + File.separator + subPath; + } + +} diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/storages/filesystem/FileUtils.java b/storage-filesystem/src/main/java/space/shefer/receipt/storages/filesystem/FileUtils.java new file mode 100644 index 0000000..0f0cde2 --- /dev/null +++ b/storage-filesystem/src/main/java/space/shefer/receipt/storages/filesystem/FileUtils.java @@ -0,0 +1,68 @@ +package space.shefer.receipt.storages.filesystem; + +import lombok.SneakyThrows; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class FileUtils { + + + /** + * @throws IllegalArgumentException if file exists + */ + @SneakyThrows + public static File createEmptyFile(String filePath) { + File f = new File(filePath); + f.getParentFile().mkdirs(); + boolean isFileCreated = f.createNewFile(); + if (!isFileCreated) { + throw new IllegalArgumentException("File " + filePath + " already exists."); + } + return f; + } + + @SneakyThrows + public static void deleteFileIfExists(String filePath) { + File f = new File(filePath); + + if (!f.exists()) { + return; + } + + Files.delete(f.toPath()); + } + + public static List getFileNamesOfDirectory(String directoryPath) { + File[] files = new File(directoryPath).listFiles(); + + if (files == null) { + throw new IllegalArgumentException("Coult not retrieve files list from directory " + directoryPath); + } + + return Stream.of(files) + .filter(File::isFile) + .map(File::getName) + .collect(Collectors.toList()); + } + + @SneakyThrows + static String readFileOrNull(String filePath) { + Path path = Paths.get(filePath); + + if (!path.toFile().exists()) { + return null; + } + + byte[] encoded = Files.readAllBytes(path); + + return new String(encoded, StandardCharsets.UTF_8); + } + +} diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/storages/filesystem/FormatType.java b/storage-filesystem/src/main/java/space/shefer/receipt/storages/filesystem/FormatType.java new file mode 100644 index 0000000..256f69b --- /dev/null +++ b/storage-filesystem/src/main/java/space/shefer/receipt/storages/filesystem/FormatType.java @@ -0,0 +1,6 @@ +package space.shefer.receipt.storages.filesystem; + +public enum FormatType { + JSON, + YAML +} From 8cfde7285e8ccd64650c91bfeb72b7a71da557ca Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Sat, 30 Jan 2021 19:38:17 +0300 Subject: [PATCH 09/30] Add receipt dto for storage-filesystem --- .../space/shefer/receipt/dto/ReceiptDto.java | 39 +++++++++++++++++++ .../shefer/receipt/dto/ReceiptItemDto.java | 13 +++++++ .../shefer/receipt/dto/ReceiptMetaDto.java | 19 +++++++++ 3 files changed, 71 insertions(+) create mode 100644 storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptDto.java create mode 100644 storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptItemDto.java create mode 100644 storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptMetaDto.java diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptDto.java b/storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptDto.java new file mode 100644 index 0000000..d4f871f --- /dev/null +++ b/storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptDto.java @@ -0,0 +1,39 @@ +package space.shefer.receipt.dto; + +import lombok.Builder; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Data +@Builder +public class ReceiptDto { + public static DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss"); + + public static String id(ReceiptDto receiptDto) { + return receiptDto.getMeta().getDateTime() + .withZoneSameInstant(ZoneId.of("UTC")) + .format(DATE_FORMATTER); + } + + @NotNull + private ReceiptMetaDto meta; + + @NotNull + private List items = new ArrayList<>(); + + @NotNull + private Set tags = new HashSet<>(); + + @NotNull + private Map other = new HashMap<>(); + +} diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptItemDto.java b/storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptItemDto.java new file mode 100644 index 0000000..cf11088 --- /dev/null +++ b/storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptItemDto.java @@ -0,0 +1,13 @@ +package space.shefer.receipt.dto; + +import lombok.Data; + +@Data +public class ReceiptItemDto { + + private String name; + private double amount; + private double price; + private double sum; + +} diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptMetaDto.java b/storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptMetaDto.java new file mode 100644 index 0000000..1882196 --- /dev/null +++ b/storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptMetaDto.java @@ -0,0 +1,19 @@ +package space.shefer.receipt.dto; + +import lombok.Data; + +import javax.annotation.Nullable; +import javax.validation.constraints.NotNull; +import java.time.ZonedDateTime; + +@Data +public class ReceiptMetaDto { + + @NotNull + private ZonedDateTime dateTime; + private int currency; + private double sum; + @Nullable + private String merchantName; + +} From 63e3b7155ea5be0bc0b1a4ef554d20b30b428988 Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Sat, 30 Jan 2021 19:37:07 +0300 Subject: [PATCH 10/30] Create ReceiptsParser, NalogReceiptsParser, TinkoffReceiptsParser --- .../receipt/parser/NalogReceiptsParser.java | 82 +++++++++++++++++ .../shefer/receipt/parser/ReceiptsParser.java | 9 ++ .../receipt/parser/TinkoffReceiptsParser.java | 87 +++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 storage-filesystem/src/main/java/space/shefer/receipt/parser/NalogReceiptsParser.java create mode 100644 storage-filesystem/src/main/java/space/shefer/receipt/parser/ReceiptsParser.java create mode 100644 storage-filesystem/src/main/java/space/shefer/receipt/parser/TinkoffReceiptsParser.java diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/parser/NalogReceiptsParser.java b/storage-filesystem/src/main/java/space/shefer/receipt/parser/NalogReceiptsParser.java new file mode 100644 index 0000000..b706cec --- /dev/null +++ b/storage-filesystem/src/main/java/space/shefer/receipt/parser/NalogReceiptsParser.java @@ -0,0 +1,82 @@ +package space.shefer.receipt.parser; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import lombok.SneakyThrows; +import org.springframework.util.ResourceUtils; +import space.shefer.receipt.dto.ReceiptDto; +import space.shefer.receipt.dto.ReceiptItemDto; +import space.shefer.receipt.dto.ReceiptMetaDto; + +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +/** + * Allows to read operations history from JSON file which was created by "Proverka Checka" mobile app. + * + * User of "Proverka checka" mobile application could sent the operations history to email. This file format is parsed by this class. + */ +public class NalogReceiptsParser implements ReceiptsParser { + + private static final ObjectMapper MAPPER = new ObjectMapper(new YAMLFactory()) + .findAndRegisterModules(); + + @SneakyThrows + @Override + public List parse(String filePath) { + ArrayNode receipts = readReceiptsJson(filePath); + + return StreamSupport.stream(receipts.spliterator(), false) + .map(receipt -> (ObjectNode) receipt.get("ticket").get("document").get("receipt")) + .map(receipt -> { + ReceiptMetaDto receiptMetaDto = getReceiptMetaDto(receipt); + List items = getItemsOfReceiptJson(receipt); + + return ReceiptDto.builder() + .meta(receiptMetaDto) + .items(items) + .build(); + }) + .collect(Collectors.toList()); + } + + @NotNull + private static ReceiptMetaDto getReceiptMetaDto(ObjectNode receipt) { + ReceiptMetaDto receiptMetaDto = new ReceiptMetaDto(); + receiptMetaDto.setCurrency(810); + receiptMetaDto.setSum(receipt.get("totalSum").asDouble() / 100.0); + receiptMetaDto.setDateTime(LocalDateTime.parse(receipt.get("dateTime").asText(), DateTimeFormatter.ISO_DATE_TIME).atZone(ZoneId.of("Europe/Moscow"))); + receiptMetaDto.setMerchantName(receipt.get("userInn").asText()); + return receiptMetaDto; + } + + @SneakyThrows + private static List getItemsOfReceiptJson(ObjectNode receipt) { + ArrayNode items = (ArrayNode) receipt.get("items"); + + return StreamSupport.stream(items.spliterator(), false) + .map(item -> getReceiptItemDto((ObjectNode) item)) + .collect(Collectors.toList()); + } + + private static ReceiptItemDto getReceiptItemDto(ObjectNode item) { + ReceiptItemDto receiptItemDto = new ReceiptItemDto(); + receiptItemDto.setName(item.get("name").asText()); + receiptItemDto.setPrice(item.get("price").asDouble() / 100.0); + receiptItemDto.setAmount(item.get("quantity").asDouble()); + receiptItemDto.setSum(item.get("sum").asDouble() / 100.0); + return receiptItemDto; + } + + @SneakyThrows + private static ArrayNode readReceiptsJson(String filePath) { + return (ArrayNode) MAPPER.readTree(ResourceUtils.getFile(filePath)); + } +} diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/parser/ReceiptsParser.java b/storage-filesystem/src/main/java/space/shefer/receipt/parser/ReceiptsParser.java new file mode 100644 index 0000000..f4014b3 --- /dev/null +++ b/storage-filesystem/src/main/java/space/shefer/receipt/parser/ReceiptsParser.java @@ -0,0 +1,9 @@ +package space.shefer.receipt.parser; + +import space.shefer.receipt.dto.ReceiptDto; + +import java.util.List; + +public interface ReceiptsParser { + List parse(String filePath); +} diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/parser/TinkoffReceiptsParser.java b/storage-filesystem/src/main/java/space/shefer/receipt/parser/TinkoffReceiptsParser.java new file mode 100644 index 0000000..d170b9f --- /dev/null +++ b/storage-filesystem/src/main/java/space/shefer/receipt/parser/TinkoffReceiptsParser.java @@ -0,0 +1,87 @@ +package space.shefer.receipt.parser; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.dataformat.csv.CsvMapper; +import com.fasterxml.jackson.dataformat.csv.CsvSchema; +import lombok.SneakyThrows; +import org.springframework.util.ResourceUtils; +import space.shefer.receipt.dto.ReceiptDto; +import space.shefer.receipt.dto.ReceiptMetaDto; + +import javax.annotation.Nullable; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * Allows to read bank operations history in CSV format which was created by Tinkoff Bank + */ +public class TinkoffReceiptsParser implements ReceiptsParser { + + private static final CsvMapper MAPPER = new CsvMapper(); + + private static final CsvSchema orderLineSchema = CsvSchema.emptySchema() + .withHeader() + .withColumnSeparator(';'); + + @SneakyThrows + @Override + public List parse(String filePath) { + List orderLines = MAPPER.readerFor(JsonNode.class) + .with(orderLineSchema) + .readValues(ResourceUtils.getFile(filePath)) + .readAll(); + + return orderLines.stream() + .map(it -> (ObjectNode) it) + .map(it -> parseReceiptMeta(it)) + .filter(Objects::nonNull) + .map(it -> ReceiptDto.builder() + .meta(it) + .items(new ArrayList<>()) + .build() + ) + .collect(Collectors.toList()); + } + + @Nullable + private ReceiptMetaDto parseReceiptMeta(ObjectNode it) { + String status = it.get("Статус").asText(); + if (!status.equals("OK")) { + return null; + } + + ReceiptMetaDto receiptMetaDto = new ReceiptMetaDto(); + + double sum = -Double.parseDouble(it.get("Сумма операции").asText().replace(",", ".")); + if (sum >= 0) { + receiptMetaDto.setSum(sum); + } + else { + return null; + } + + receiptMetaDto.setDateTime(LocalDateTime.parse(it.get("Дата операции").asText(), DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss")).atZone(ZoneId.of("Europe/Moscow"))); + receiptMetaDto.setMerchantName(it.get("Описание").asText()); + + receiptMetaDto.setCurrency(resolveCurrencyCode(it.get("Валюта операции").asText())); + + return receiptMetaDto; + } + + private int resolveCurrencyCode(String currencyName) { + int currency; + if(currencyName.equals("RUB")) { + currency = 810; + } else{ + currency = 0; + } + return currency; + } + +} From dc76dc421aa76ac36828e0fe704bdf9721eb29ed Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Sat, 30 Jan 2021 19:53:14 +0300 Subject: [PATCH 11/30] dsfaf --- .../space/shefer/receipt/parser/NalogReceiptsParser.java | 9 +++++---- .../java/space/shefer/receipt/parser/ReceiptsParser.java | 3 ++- .../shefer/receipt/parser/TinkoffReceiptsParser.java | 5 +++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/parser/NalogReceiptsParser.java b/storage-filesystem/src/main/java/space/shefer/receipt/parser/NalogReceiptsParser.java index b706cec..5577bb7 100644 --- a/storage-filesystem/src/main/java/space/shefer/receipt/parser/NalogReceiptsParser.java +++ b/storage-filesystem/src/main/java/space/shefer/receipt/parser/NalogReceiptsParser.java @@ -11,6 +11,7 @@ import space.shefer.receipt.dto.ReceiptMetaDto; import javax.validation.constraints.NotNull; +import java.io.File; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; @@ -30,8 +31,8 @@ public class NalogReceiptsParser implements ReceiptsParser { @SneakyThrows @Override - public List parse(String filePath) { - ArrayNode receipts = readReceiptsJson(filePath); + public List parse(File file) { + ArrayNode receipts = readReceiptsJson(file); return StreamSupport.stream(receipts.spliterator(), false) .map(receipt -> (ObjectNode) receipt.get("ticket").get("document").get("receipt")) @@ -76,7 +77,7 @@ private static ReceiptItemDto getReceiptItemDto(ObjectNode item) { } @SneakyThrows - private static ArrayNode readReceiptsJson(String filePath) { - return (ArrayNode) MAPPER.readTree(ResourceUtils.getFile(filePath)); + private static ArrayNode readReceiptsJson(File file) { + return (ArrayNode) MAPPER.readTree(file); } } diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/parser/ReceiptsParser.java b/storage-filesystem/src/main/java/space/shefer/receipt/parser/ReceiptsParser.java index f4014b3..ec9c682 100644 --- a/storage-filesystem/src/main/java/space/shefer/receipt/parser/ReceiptsParser.java +++ b/storage-filesystem/src/main/java/space/shefer/receipt/parser/ReceiptsParser.java @@ -2,8 +2,9 @@ import space.shefer.receipt.dto.ReceiptDto; +import java.io.File; import java.util.List; public interface ReceiptsParser { - List parse(String filePath); + List parse(File file); } diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/parser/TinkoffReceiptsParser.java b/storage-filesystem/src/main/java/space/shefer/receipt/parser/TinkoffReceiptsParser.java index d170b9f..7d07303 100644 --- a/storage-filesystem/src/main/java/space/shefer/receipt/parser/TinkoffReceiptsParser.java +++ b/storage-filesystem/src/main/java/space/shefer/receipt/parser/TinkoffReceiptsParser.java @@ -10,6 +10,7 @@ import space.shefer.receipt.dto.ReceiptMetaDto; import javax.annotation.Nullable; +import java.io.File; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; @@ -31,10 +32,10 @@ public class TinkoffReceiptsParser implements ReceiptsParser { @SneakyThrows @Override - public List parse(String filePath) { + public List parse(File file) { List orderLines = MAPPER.readerFor(JsonNode.class) .with(orderLineSchema) - .readValues(ResourceUtils.getFile(filePath)) + .readValues(file) .readAll(); return orderLines.stream() From 593c34832e1dd0fb00ec7d60cb1ef11c2ff3b396 Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Thu, 11 Feb 2021 16:20:53 +0300 Subject: [PATCH 12/30] Add tags of source type for parsed receipts --- .../java/space/shefer/receipt/parser/NalogReceiptsParser.java | 4 +++- .../space/shefer/receipt/parser/TinkoffReceiptsParser.java | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/parser/NalogReceiptsParser.java b/storage-filesystem/src/main/java/space/shefer/receipt/parser/NalogReceiptsParser.java index 5577bb7..39fc409 100644 --- a/storage-filesystem/src/main/java/space/shefer/receipt/parser/NalogReceiptsParser.java +++ b/storage-filesystem/src/main/java/space/shefer/receipt/parser/NalogReceiptsParser.java @@ -5,7 +5,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import lombok.SneakyThrows; -import org.springframework.util.ResourceUtils; import space.shefer.receipt.dto.ReceiptDto; import space.shefer.receipt.dto.ReceiptItemDto; import space.shefer.receipt.dto.ReceiptMetaDto; @@ -15,6 +14,8 @@ import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -43,6 +44,7 @@ public List parse(File file) { return ReceiptDto.builder() .meta(receiptMetaDto) .items(items) + .tags(new HashSet<>(Arrays.asList("nalog"))) .build(); }) .collect(Collectors.toList()); diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/parser/TinkoffReceiptsParser.java b/storage-filesystem/src/main/java/space/shefer/receipt/parser/TinkoffReceiptsParser.java index 7d07303..fbba792 100644 --- a/storage-filesystem/src/main/java/space/shefer/receipt/parser/TinkoffReceiptsParser.java +++ b/storage-filesystem/src/main/java/space/shefer/receipt/parser/TinkoffReceiptsParser.java @@ -15,6 +15,8 @@ import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -45,6 +47,7 @@ public List parse(File file) { .map(it -> ReceiptDto.builder() .meta(it) .items(new ArrayList<>()) + .tags(new HashSet<>(Arrays.asList("tinkoff"))) .build() ) .collect(Collectors.toList()); From 2aaf1a1a0c8d8dfe32186444ddb0a8a3bdd11c36 Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Thu, 11 Feb 2021 16:56:43 +0300 Subject: [PATCH 13/30] Remove /create endpoint --- .../core/service/UserProfileService.java | 47 -------- .../rest/controller/ReceiptController.java | 29 ----- .../controller/ReceiptControllerTest.java | 101 ------------------ 3 files changed, 177 deletions(-) delete mode 100644 core/src/main/java/space/shefer/receipt/platform/core/service/UserProfileService.java delete mode 100644 rest-api/src/test/java/space/shefer/receipt/rest/controller/ReceiptControllerTest.java diff --git a/core/src/main/java/space/shefer/receipt/platform/core/service/UserProfileService.java b/core/src/main/java/space/shefer/receipt/platform/core/service/UserProfileService.java deleted file mode 100644 index e3e7e0e..0000000 --- a/core/src/main/java/space/shefer/receipt/platform/core/service/UserProfileService.java +++ /dev/null @@ -1,47 +0,0 @@ -package space.shefer.receipt.platform.core.service; - -import org.springframework.beans.factory.annotation.Autowired; -import javax.annotation.Nullable; -import org.springframework.stereotype.Service; -import space.shefer.receipt.platform.core.entity.UserProfile; -import space.shefer.receipt.platform.core.repository.UserProfileRepository; - - -import java.util.UUID; - -@Service -public class UserProfileService { - - private final UserProfileRepository userProfileRepository; - - @Autowired - public UserProfileService(UserProfileRepository userProfileRepository) { - this.userProfileRepository = userProfileRepository; - } - - public UserProfile createOrUpdate(String phone, String password) { - UserProfile userProfile = userProfileRepository.getByPhone(phone); - if (userProfile == null) { - UserProfile resultUser = new UserProfile(); - resultUser.setPassword(password); - resultUser.setPhone(phone); - resultUser.setAccessToken(UUID.randomUUID().toString()); - return userProfileRepository.save(resultUser); - } - if (!userProfile.getPassword().equals(password)) { - userProfile.setPassword(password); - userProfile.setPhone(phone); - return userProfileRepository.save(userProfile); - } - return userProfile; - } - - @Nullable - public UserProfile getUserByToken(@Nullable String token) { - if (token == null) { - return null; - } - return userProfileRepository.getByAccessToken(token); - } - -} diff --git a/rest-api/src/main/java/space/shefer/receipt/rest/controller/ReceiptController.java b/rest-api/src/main/java/space/shefer/receipt/rest/controller/ReceiptController.java index 6836507..1db098f 100644 --- a/rest-api/src/main/java/space/shefer/receipt/rest/controller/ReceiptController.java +++ b/rest-api/src/main/java/space/shefer/receipt/rest/controller/ReceiptController.java @@ -5,47 +5,18 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.lang.Nullable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import space.shefer.receipt.platform.core.entity.Receipt; -import space.shefer.receipt.platform.core.entity.UserProfile; -import space.shefer.receipt.platform.core.service.UserProfileService; -import space.shefer.receipt.rest.converters.ReceiptMetaConverter; -import space.shefer.receipt.rest.dto.ReceiptCreateDto; -import space.shefer.receipt.rest.dto.ReceiptMetaDto; import space.shefer.receipt.rest.service.ReceiptService; -import javax.validation.Valid; - @Tag(name = "Receipts management") @RestController @RequiredArgsConstructor public class ReceiptController { private final ReceiptService receiptService; - private final UserProfileService userProfileService; - - @Operation( - description = "Submit receipt for loading. If receipt is submitted " + - "multiple times, then deduplication could be performed.", - responses = @ApiResponse(responseCode = "200", description = "Receipt has been successfully created") - ) - @RequestMapping(value = "/create", method = RequestMethod.POST) - public ReceiptMetaDto create(@Valid @RequestBody ReceiptCreateDto query, - @Nullable @RequestHeader("Authorization") String authHeader) { - UserProfile userProfile = null; - if (authHeader != null) { - String token = authHeader.substring("Bearer ".length()); - userProfile = userProfileService.getUserByToken(token); - } - Receipt receipt = receiptService.create(query, userProfile); - return ReceiptMetaConverter.toDto(receipt); - } @Operation( description = "Allows remove receipt if it is stuck in loading", diff --git a/rest-api/src/test/java/space/shefer/receipt/rest/controller/ReceiptControllerTest.java b/rest-api/src/test/java/space/shefer/receipt/rest/controller/ReceiptControllerTest.java deleted file mode 100644 index 72aeabd..0000000 --- a/rest-api/src/test/java/space/shefer/receipt/rest/controller/ReceiptControllerTest.java +++ /dev/null @@ -1,101 +0,0 @@ -package space.shefer.receipt.rest.controller; - -import lombok.SneakyThrows; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import space.shefer.receipt.platform.core.entity.Receipt; -import space.shefer.receipt.platform.core.entity.UserProfile; -import space.shefer.receipt.platform.core.service.UserProfileService; -import space.shefer.receipt.platform.core.util.DateUtil; -import space.shefer.receipt.rest.dto.ReceiptCreateDto; -import space.shefer.receipt.rest.service.ReceiptService; -import space.shefer.receipt.tests.util.ResourceUtil; - -import java.nio.file.Paths; -import java.util.Scanner; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -public class ReceiptControllerTest { - - private MockMvc mockMvc; - private ReceiptController controller; - private ReceiptService receiptService; - private UserProfileService userProfileService; - - @Before - public void setUp() { - receiptService = mock(ReceiptService.class); - userProfileService = mock(UserProfileService.class); - controller = spy(new ReceiptController(receiptService, userProfileService)); - mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); - } - - @Test - @SneakyThrows - public void create_withoutToken() { - String body = ResourceUtil.getResourceAsString("/controller/ReceiptCreateControllerTest_create.json", getClass()); - doAnswer(n -> new Receipt()).when(receiptService).create(any(), isNull()); - mockMvc.perform(post("/create").content(body) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()); - ArgumentCaptor createDtoCaptor = ArgumentCaptor.forClass(ReceiptCreateDto.class); - verify(receiptService, times(1)).create(createDtoCaptor.capture(), isNull()); - ReceiptCreateDto receiptCreateDto = createDtoCaptor.getValue(); - assertEquals(DateUtil.parseReceiptDate("20190801T1032"), receiptCreateDto.getDate()); - assertEquals(123629, receiptCreateDto.getSum(), 1e-5); - assertEquals("9282000100338973", receiptCreateDto.getFn()); - assertEquals("832555", receiptCreateDto.getFd()); - assertEquals("535594", receiptCreateDto.getFp()); - } - - @Test - @SneakyThrows - public void create_withToken() { - String testToken = "56hty46eyfh"; - UserProfile userProfile = new UserProfile(); - String body = ResourceUtil.getResourceAsString("/controller/ReceiptCreateControllerTest_create.json", getClass()); - doAnswer(n -> new Receipt()).when(receiptService).create(any(), argThat(it -> it.equals(userProfile))); - doAnswer(__ -> userProfile).when(userProfileService).getUserByToken(testToken); - mockMvc.perform(post("/create").content(body) - .header("Authorization", "Bearer " + testToken) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()); - ArgumentCaptor createDtoCaptor = ArgumentCaptor.forClass(ReceiptCreateDto.class); - verify(receiptService, times(1)).create(createDtoCaptor.capture(), eq(userProfile)); - ReceiptCreateDto receiptCreateDto = createDtoCaptor.getValue(); - assertEquals(DateUtil.parseReceiptDate("20190801T1032"), receiptCreateDto.getDate()); - assertEquals(123629, receiptCreateDto.getSum(), 1e-5); - assertEquals("9282000100338973", receiptCreateDto.getFn()); - assertEquals("832555", receiptCreateDto.getFd()); - assertEquals("535594", receiptCreateDto.getFp()); - } - - @Test - @SneakyThrows - public void create_checkValidityInputData() { - String[] jsons = ResourceUtil.getResourceAsString("/controller/BadJSONRequests.txt", getClass()).split("---"); - doAnswer(n -> new Receipt()).when(receiptService).create(any(), isNull()); - for(String json: jsons){ - mockMvc.perform(post("/create").content(json) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isBadRequest()); - } - } - -} From 143fa1bfa2a885ad0969f25e832a62b50aaf779a Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Fri, 12 Feb 2021 18:08:43 +0300 Subject: [PATCH 14/30] New module storage-filesystem --- settings.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/settings.gradle b/settings.gradle index 4b19543..1f059ef 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,6 +8,7 @@ include 'jobs' include 'fns-sdk' include 'rest-api' include 'rest-api-dto' +include 'storage-filesystem' include 'telegram-bot' include 'test-util' From ec70e7c143f2ebaaea762c73c36d614b183cc3aa Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Fri, 12 Feb 2021 18:09:07 +0300 Subject: [PATCH 15/30] Add actuator to rest-api --- rest-api/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/rest-api/build.gradle b/rest-api/build.gradle index 05a8ce9..87e360e 100644 --- a/rest-api/build.gradle +++ b/rest-api/build.gradle @@ -12,6 +12,7 @@ dependencies { implementation 'commons-codec:commons-codec' implementation 'org.apache.commons:commons-lang3' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework:spring-context-support' implementation 'org.projectlombok:lombok' implementation 'org.springdoc:springdoc-openapi-ui' From e6588790344b70659b660b908d9d4704ed14ed0e Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Fri, 12 Feb 2021 18:09:38 +0300 Subject: [PATCH 16/30] Add method deleteAll to Dao --- .../main/java/space/shefer/receipt/storages/Dao.java | 3 +++ .../receipt/storages/filesystem/FileSystemDao.java | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/storages/Dao.java b/storage-filesystem/src/main/java/space/shefer/receipt/storages/Dao.java index 276e198..dac3cc4 100644 --- a/storage-filesystem/src/main/java/space/shefer/receipt/storages/Dao.java +++ b/storage-filesystem/src/main/java/space/shefer/receipt/storages/Dao.java @@ -6,6 +6,9 @@ public interface Dao { T save(String id, T entity); + + void deleteAll(); + T getById(String id); @Nullable T getByIdOrNull(String id); diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/storages/filesystem/FileSystemDao.java b/storage-filesystem/src/main/java/space/shefer/receipt/storages/filesystem/FileSystemDao.java index 10e91ed..40c40c4 100644 --- a/storage-filesystem/src/main/java/space/shefer/receipt/storages/filesystem/FileSystemDao.java +++ b/storage-filesystem/src/main/java/space/shefer/receipt/storages/filesystem/FileSystemDao.java @@ -51,6 +51,18 @@ public void delete(String id) { deleteFileIfExists(getFilePath(id)); } + @Override + public void deleteAll() { + File directory = new File(getDirectoryPath()); + if (directory.exists()) { + for (File file : directory.listFiles()) { + if (!file.isDirectory()) { + file.delete(); + } + } + } + } + @SneakyThrows @Override public T getById(String id) { From 2d7f55d323bf31304a47a845b17c81e1939a6712 Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Fri, 12 Feb 2021 18:11:00 +0300 Subject: [PATCH 17/30] Allow parse directories by ReceiptsParser --- .../receipt/parser/NalogReceiptsParser.java | 14 +++---- .../shefer/receipt/parser/ReceiptsParser.java | 41 ++++++++++++++++++- .../receipt/parser/TinkoffReceiptsParser.java | 15 +++---- 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/parser/NalogReceiptsParser.java b/storage-filesystem/src/main/java/space/shefer/receipt/parser/NalogReceiptsParser.java index 39fc409..b199afb 100644 --- a/storage-filesystem/src/main/java/space/shefer/receipt/parser/NalogReceiptsParser.java +++ b/storage-filesystem/src/main/java/space/shefer/receipt/parser/NalogReceiptsParser.java @@ -32,7 +32,7 @@ public class NalogReceiptsParser implements ReceiptsParser { @SneakyThrows @Override - public List parse(File file) { + public List parseFile(File file) { ArrayNode receipts = readReceiptsJson(file); return StreamSupport.stream(receipts.spliterator(), false) @@ -52,12 +52,12 @@ public List parse(File file) { @NotNull private static ReceiptMetaDto getReceiptMetaDto(ObjectNode receipt) { - ReceiptMetaDto receiptMetaDto = new ReceiptMetaDto(); - receiptMetaDto.setCurrency(810); - receiptMetaDto.setSum(receipt.get("totalSum").asDouble() / 100.0); - receiptMetaDto.setDateTime(LocalDateTime.parse(receipt.get("dateTime").asText(), DateTimeFormatter.ISO_DATE_TIME).atZone(ZoneId.of("Europe/Moscow"))); - receiptMetaDto.setMerchantName(receipt.get("userInn").asText()); - return receiptMetaDto; + return ReceiptMetaDto.builder() + .currency(810) + .sum(receipt.get("totalSum").asDouble() / 100.0) + .dateTime(LocalDateTime.parse(receipt.get("dateTime").asText(), DateTimeFormatter.ISO_DATE_TIME).atZone(ZoneId.of("Europe/Moscow"))) + .merchantName(receipt.get("userInn").asText()) + .build(); } @SneakyThrows diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/parser/ReceiptsParser.java b/storage-filesystem/src/main/java/space/shefer/receipt/parser/ReceiptsParser.java index ec9c682..03c9a41 100644 --- a/storage-filesystem/src/main/java/space/shefer/receipt/parser/ReceiptsParser.java +++ b/storage-filesystem/src/main/java/space/shefer/receipt/parser/ReceiptsParser.java @@ -3,8 +3,47 @@ import space.shefer.receipt.dto.ReceiptDto; import java.io.File; +import java.util.ArrayList; import java.util.List; +import java.util.Objects; public interface ReceiptsParser { - List parse(File file); + + List parseFile(File file); + + /** + * Recursively reads all files of directory if directory passed or reads yhe file if file passed and then parses and merges results into list of receipts. + * + * @param file file or directory + * @return list of receipts + * @throws IllegalArgumentException if neither file nor directory passed. + */ + default List parse(File file) { + if (file.isFile()) { + return parseFile(file); + } + + if (file.isDirectory()) { + List result = new ArrayList<>(); + for (File listFile : Objects.requireNonNull(file.listFiles())) { + result = merge(result, parse(listFile)); + } + return result; + } + + throw new IllegalArgumentException("Path is neither file not directory: " + file.toString()); + } + + /** + * Merge two lists of the same provider receipts. + * Mainly used to concatenate two lists omitting the duplicates. + * The incoming and resulting lists could be unsorted. + */ + default List merge(List list1, List list2) { + ArrayList result = new ArrayList<>(list1); + result.addAll(list2); + return result; + } + + ; } diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/parser/TinkoffReceiptsParser.java b/storage-filesystem/src/main/java/space/shefer/receipt/parser/TinkoffReceiptsParser.java index fbba792..64d6f24 100644 --- a/storage-filesystem/src/main/java/space/shefer/receipt/parser/TinkoffReceiptsParser.java +++ b/storage-filesystem/src/main/java/space/shefer/receipt/parser/TinkoffReceiptsParser.java @@ -8,6 +8,7 @@ import org.springframework.util.ResourceUtils; import space.shefer.receipt.dto.ReceiptDto; import space.shefer.receipt.dto.ReceiptMetaDto; +import space.shefer.receipt.dto.ReceiptMetaDto.ReceiptMetaDtoBuilder; import javax.annotation.Nullable; import java.io.File; @@ -34,7 +35,7 @@ public class TinkoffReceiptsParser implements ReceiptsParser { @SneakyThrows @Override - public List parse(File file) { + public List parseFile(File file) { List orderLines = MAPPER.readerFor(JsonNode.class) .with(orderLineSchema) .readValues(file) @@ -60,22 +61,22 @@ private ReceiptMetaDto parseReceiptMeta(ObjectNode it) { return null; } - ReceiptMetaDto receiptMetaDto = new ReceiptMetaDto(); + ReceiptMetaDtoBuilder receiptMetaDto = ReceiptMetaDto.builder(); double sum = -Double.parseDouble(it.get("Сумма операции").asText().replace(",", ".")); if (sum >= 0) { - receiptMetaDto.setSum(sum); + receiptMetaDto.sum(sum); } else { return null; } - receiptMetaDto.setDateTime(LocalDateTime.parse(it.get("Дата операции").asText(), DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss")).atZone(ZoneId.of("Europe/Moscow"))); - receiptMetaDto.setMerchantName(it.get("Описание").asText()); + receiptMetaDto.dateTime(LocalDateTime.parse(it.get("Дата операции").asText(), DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss")).atZone(ZoneId.of("Europe/Moscow"))); + receiptMetaDto.merchantName(it.get("Описание").asText()); - receiptMetaDto.setCurrency(resolveCurrencyCode(it.get("Валюта операции").asText())); + receiptMetaDto.currency(resolveCurrencyCode(it.get("Валюта операции").asText())); - return receiptMetaDto; + return receiptMetaDto.build(); } private int resolveCurrencyCode(String currencyName) { From 30f5e8df7c50411101a08a58b00fa36421ab7ab2 Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Fri, 12 Feb 2021 18:11:30 +0300 Subject: [PATCH 18/30] Add Main.java in storage-filesystem --- .../space/shefer/receipt/parser/Main.java | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 storage-filesystem/src/main/java/space/shefer/receipt/parser/Main.java diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/parser/Main.java b/storage-filesystem/src/main/java/space/shefer/receipt/parser/Main.java new file mode 100644 index 0000000..5b4a42c --- /dev/null +++ b/storage-filesystem/src/main/java/space/shefer/receipt/parser/Main.java @@ -0,0 +1,119 @@ +package space.shefer.receipt.parser; + +import lombok.SneakyThrows; +import org.springframework.util.ResourceUtils; +import space.shefer.receipt.dto.ReceiptDto; +import space.shefer.receipt.dto.ReceiptItemDto; +import space.shefer.receipt.dto.ReceiptMetaDto; +import space.shefer.receipt.storages.Dao; +import space.shefer.receipt.storages.filesystem.FileSystemDao; +import space.shefer.receipt.storages.filesystem.FormatType; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +public class Main { + + private static final String ROOT_DIRECTORY = "workdir"; + private static final String SOURCE_DIRECTORY = ROOT_DIRECTORY + "/source"; + private static final String OUTPUT_DIRECTORY = ROOT_DIRECTORY + "/output"; + + private static final Dao receiptDao = new FileSystemDao<>(OUTPUT_DIRECTORY, "receipts", FormatType.YAML, Object.class); + + private static final ReceiptsParser nalogReceiptsParser = new NalogReceiptsParser(); + private static final ReceiptsParser tinkoffReceiptsParser = new TinkoffReceiptsParser(); + + @SneakyThrows + public static void main(String[] args) { + receiptDao.deleteAll(); + + List receiptsNalog = nalogReceiptsParser.parse(ResourceUtils.getFile(SOURCE_DIRECTORY + "/nalog")); + List receiptsTinkoff = tinkoffReceiptsParser.parse(ResourceUtils.getFile(SOURCE_DIRECTORY + "/tinkoff")); + + Set objects = new HashSet<>(); + objects.addAll(receiptsNalog); + objects.addAll(receiptsTinkoff); + + Map> collect = objects.stream().collect(Collectors.groupingBy(ReceiptDto::id)); + + for (Map.Entry> id2receiptList : collect.entrySet()) { + String id = id2receiptList.getKey(); + Set receiptsOfId = new HashSet<>(id2receiptList.getValue()); + ReceiptDto receiptMerged = mergeReceipts(receiptsOfId); + receiptDao.save(receiptsOfId.size() + "_" + id, receiptMerged); + } + + } + + private static ReceiptDto mergeReceipts(Set receiptsOfId) { + if (receiptsOfId.size() == 1) { + return receiptsOfId.stream().findFirst().get(); + } + + String merchantName = receiptsOfId.stream() + .map(ReceiptDto::getMeta) + .map(ReceiptMetaDto::getMerchantName) + .flatMap(it -> Arrays.stream(it.split("\\|"))) + .map(String::trim) + .distinct() + .sorted() + .collect(Collectors.joining(" | ")); + + List sums = receiptsOfId.stream() + .map(ReceiptDto::getMeta) + .map(ReceiptMetaDto::getSum) + .distinct() + .collect(Collectors.toList()); + if (sums.size() > 1) throw new IllegalArgumentException("Unmergeable receipts: Different sums: " + sums); + Double sum = sums.get(0); + + List currencies = receiptsOfId.stream() + .map(ReceiptDto::getMeta) + .map(ReceiptMetaDto::getCurrency) + .distinct() + .collect(Collectors.toList()); + if (currencies.size() > 1) + throw new IllegalArgumentException("Unmergeable receipts: Different currencies: " + sums); + int currency = currencies.get(0); + + List items = receiptsOfId.stream() + .map(ReceiptDto::getItems) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toList()); + + Set tags = receiptsOfId.stream() + .map(ReceiptDto::getTags) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + + Map other = receiptsOfId.stream() + .map(ReceiptDto::getOther) + .filter(Objects::nonNull) + .reduce(new HashMap<>(), (a, b) -> { + a.putAll(b); + return a; + }); + + ReceiptDto receiptMerged = ReceiptDto.builder() + .meta(ReceiptMetaDto.builder() + .merchantName(merchantName) + .sum(sum) + .currency(currency) + .dateTime(receiptsOfId.stream().findFirst().get().getMeta().getDateTime()) + .build()) + .items(items) + .tags(tags) + .other(other) + .build(); + return receiptMerged; + } + +} From 5e41a0f5db46ccf39dbf9c5e419df96facf49aa8 Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Fri, 12 Feb 2021 18:12:47 +0300 Subject: [PATCH 19/30] Add builder to ReceiptMetaDto.java --- .../main/java/space/shefer/receipt/dto/ReceiptMetaDto.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptMetaDto.java b/storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptMetaDto.java index 1882196..685d8ef 100644 --- a/storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptMetaDto.java +++ b/storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptMetaDto.java @@ -1,5 +1,7 @@ package space.shefer.receipt.dto; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Builder; import lombok.Data; import javax.annotation.Nullable; @@ -7,9 +9,11 @@ import java.time.ZonedDateTime; @Data +@Builder public class ReceiptMetaDto { @NotNull + @JsonFormat(pattern = "yyyyMMdd'T'HHmmss") private ZonedDateTime dateTime; private int currency; private double sum; From b8afc4b5a083d83775d6cdada6b3d66fa3fa385a Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Fri, 12 Feb 2021 18:13:06 +0300 Subject: [PATCH 20/30] Refactoring in ReceiptDto.java --- .../space/shefer/receipt/dto/ReceiptDto.java | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptDto.java b/storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptDto.java index d4f871f..7738adf 100644 --- a/storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptDto.java +++ b/storage-filesystem/src/main/java/space/shefer/receipt/dto/ReceiptDto.java @@ -3,12 +3,8 @@ import lombok.Builder; import lombok.Data; -import javax.validation.constraints.NotNull; import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -16,24 +12,18 @@ @Data @Builder public class ReceiptDto { - public static DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss"); + public static DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss"); public static String id(ReceiptDto receiptDto) { return receiptDto.getMeta().getDateTime() .withZoneSameInstant(ZoneId.of("UTC")) - .format(DATE_FORMATTER); + .format(DATE_FORMATTER) + + "_" + (long) receiptDto.getMeta().getSum(); } - @NotNull private ReceiptMetaDto meta; - - @NotNull - private List items = new ArrayList<>(); - - @NotNull - private Set tags = new HashSet<>(); - - @NotNull - private Map other = new HashMap<>(); + private List items; + private Set tags; + private Map other; } From d44733d7081db20c62e233e16e1ed60b1817dcb8 Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Fri, 12 Feb 2021 18:16:55 +0300 Subject: [PATCH 21/30] Remove unused 'jobs' module --- jobs/README.md | 14 ---------- jobs/build.gradle | 16 ------------ .../platform/jobs/JobsApplication.java | 16 ------------ .../platform/jobs/service/ReceiptService.java | 26 ------------------- settings.gradle | 1 - 5 files changed, 73 deletions(-) delete mode 100644 jobs/README.md delete mode 100644 jobs/build.gradle delete mode 100644 jobs/src/main/java/space/shefer/receipt/platform/jobs/JobsApplication.java delete mode 100644 jobs/src/main/java/space/shefer/receipt/platform/jobs/service/ReceiptService.java diff --git a/jobs/README.md b/jobs/README.md deleted file mode 100644 index 9d74ff3..0000000 --- a/jobs/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# jobs - -## Description -Periodical or scheduled or cron tasks - -Example: -- Receipts fetching -- Merchants fetching - -## Technologies -- Java -- Spring - - Data - - Scheduling diff --git a/jobs/build.gradle b/jobs/build.gradle deleted file mode 100644 index a9752ba..0000000 --- a/jobs/build.gradle +++ /dev/null @@ -1,16 +0,0 @@ -plugins { - id 'io.freefair.lombok' - id 'org.springframework.boot' -} - -dependencies { - implementation project(':core') - implementation project(':core-dto') - - implementation 'com.google.code.findbugs:jsr305' - implementation 'org.apache.commons:commons-lang3' - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springframework:spring-context-support' - implementation 'org.projectlombok:lombok' - -} diff --git a/jobs/src/main/java/space/shefer/receipt/platform/jobs/JobsApplication.java b/jobs/src/main/java/space/shefer/receipt/platform/jobs/JobsApplication.java deleted file mode 100644 index e8665b8..0000000 --- a/jobs/src/main/java/space/shefer/receipt/platform/jobs/JobsApplication.java +++ /dev/null @@ -1,16 +0,0 @@ -package space.shefer.receipt.platform.jobs; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Import; -import org.springframework.scheduling.annotation.EnableScheduling; -import space.shefer.receipt.platform.core.ReceiptCoreConfiguration; - -@EnableScheduling -@Import(ReceiptCoreConfiguration.class) -@SpringBootApplication -public class JobsApplication { - public static void main(String[] args) { - SpringApplication.run(JobsApplication.class, args); - } -} diff --git a/jobs/src/main/java/space/shefer/receipt/platform/jobs/service/ReceiptService.java b/jobs/src/main/java/space/shefer/receipt/platform/jobs/service/ReceiptService.java deleted file mode 100644 index cf177cd..0000000 --- a/jobs/src/main/java/space/shefer/receipt/platform/jobs/service/ReceiptService.java +++ /dev/null @@ -1,26 +0,0 @@ -package space.shefer.receipt.platform.jobs.service; - -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import space.shefer.receipt.platform.core.dto.ReceiptStatus; -import space.shefer.receipt.platform.core.entity.Receipt; -import space.shefer.receipt.platform.core.repository.ReceiptRepository; - -import java.util.List; - -@Service -@RequiredArgsConstructor -public class ReceiptService { - - private final ReceiptRepository receiptRepository; - - public List getAllIdle() { - return receiptRepository.findAllIdle(); - } - - public Receipt setStatus(Receipt receipt, ReceiptStatus status) { - receipt.setStatus(status); - return receiptRepository.save(receipt); - } - -} diff --git a/settings.gradle b/settings.gradle index 1f059ef..6893793 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,7 +4,6 @@ rootProject.name = 'receipt-java' include 'core' include 'core-dto' include 'importer-email' -include 'jobs' include 'fns-sdk' include 'rest-api' include 'rest-api-dto' From 27e9281aab62ce9ee89593914df43f702c08c1ab Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Fri, 12 Feb 2021 18:27:41 +0300 Subject: [PATCH 22/30] Extract 'merchants-resolver' module --- merchants-resolver/README.md | 3 +++ merchants-resolver/build.gradle | 15 +++++++++++++++ .../merchants/config/EnableMerchantsResolver.kt | 6 ++++++ .../config/MerchantsResolverConfiguration.kt | 8 ++++++++ .../merchants}/primainform/MerchantSuggestion.kt | 2 +- .../merchants}/primainform/MerchantSuggestions.kt | 2 +- .../merchants}/primainform/MerhcantInfo.kt | 2 +- .../receipt/merchants}/service/MerchantService.kt | 6 +++--- .../merchants}/webclient/PrimaInformWebClient.kt | 4 ++-- .../receipt/merchants}/service/MerchantDtoTest.kt | 4 ++-- settings.gradle | 1 + 11 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 merchants-resolver/README.md create mode 100644 merchants-resolver/build.gradle create mode 100644 merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/config/EnableMerchantsResolver.kt create mode 100644 merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/config/MerchantsResolverConfiguration.kt rename {fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk => merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants}/primainform/MerchantSuggestion.kt (73%) rename {fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk => merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants}/primainform/MerchantSuggestions.kt (63%) rename {fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk => merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants}/primainform/MerhcantInfo.kt (73%) rename {fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk => merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants}/service/MerchantService.kt (70%) rename {fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk => merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants}/webclient/PrimaInformWebClient.kt (83%) rename {fns-sdk/src/test/kotlin/space/shefer/receipt/fnssdk => merchants-resolver/src/test/kotlin/space/shefer/receipt/merchants}/service/MerchantDtoTest.kt (92%) diff --git a/merchants-resolver/README.md b/merchants-resolver/README.md new file mode 100644 index 0000000..b137695 --- /dev/null +++ b/merchants-resolver/README.md @@ -0,0 +1,3 @@ +# Merchants resolver + +Allows to resolve merchant readable name by inn diff --git a/merchants-resolver/build.gradle b/merchants-resolver/build.gradle new file mode 100644 index 0000000..9226873 --- /dev/null +++ b/merchants-resolver/build.gradle @@ -0,0 +1,15 @@ +plugins { + id 'kotlin-spring' +} + +dependencies { + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' + implementation 'com.fasterxml.jackson.module:jackson-module-kotlin' + implementation "org.apache.commons:commons-lang3" + implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' + implementation 'org.springframework:spring-web' + implementation 'org.springframework:spring-context-support' + + testImplementation project(':test-util') + testImplementation "org.springframework.boot:spring-boot-starter-test" +} diff --git a/merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/config/EnableMerchantsResolver.kt b/merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/config/EnableMerchantsResolver.kt new file mode 100644 index 0000000..c5ba904 --- /dev/null +++ b/merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/config/EnableMerchantsResolver.kt @@ -0,0 +1,6 @@ +package space.shefer.receipt.merchants.config + +import org.springframework.context.annotation.Import + +@Import(MerchantsResolverConfiguration::class) +annotation class EnableMerchantsResolver diff --git a/merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/config/MerchantsResolverConfiguration.kt b/merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/config/MerchantsResolverConfiguration.kt new file mode 100644 index 0000000..acbd752 --- /dev/null +++ b/merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/config/MerchantsResolverConfiguration.kt @@ -0,0 +1,8 @@ +package space.shefer.receipt.merchants.config + +import org.springframework.context.annotation.ComponentScan +import org.springframework.context.annotation.Configuration + +@ComponentScan("space.shefer.receipt.merchants") +@Configuration +class MerchantsResolverConfiguration diff --git a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/primainform/MerchantSuggestion.kt b/merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/primainform/MerchantSuggestion.kt similarity index 73% rename from fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/primainform/MerchantSuggestion.kt rename to merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/primainform/MerchantSuggestion.kt index 94cc0db..2a56281 100644 --- a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/primainform/MerchantSuggestion.kt +++ b/merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/primainform/MerchantSuggestion.kt @@ -1,4 +1,4 @@ -package space.shefer.receipt.fnssdk.primainform +package space.shefer.receipt.merchants.primainform class MerchantSuggestion { diff --git a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/primainform/MerchantSuggestions.kt b/merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/primainform/MerchantSuggestions.kt similarity index 63% rename from fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/primainform/MerchantSuggestions.kt rename to merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/primainform/MerchantSuggestions.kt index 32c4942..750e65e 100644 --- a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/primainform/MerchantSuggestions.kt +++ b/merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/primainform/MerchantSuggestions.kt @@ -1,4 +1,4 @@ -package space.shefer.receipt.fnssdk.primainform +package space.shefer.receipt.merchants.primainform class MerchantSuggestions { diff --git a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/primainform/MerhcantInfo.kt b/merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/primainform/MerhcantInfo.kt similarity index 73% rename from fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/primainform/MerhcantInfo.kt rename to merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/primainform/MerhcantInfo.kt index 53211bf..a62e21e 100644 --- a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/primainform/MerhcantInfo.kt +++ b/merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/primainform/MerhcantInfo.kt @@ -1,4 +1,4 @@ -package space.shefer.receipt.fnssdk.primainform +package space.shefer.receipt.merchants.primainform open class MerhcantInfo { diff --git a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/service/MerchantService.kt b/merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/service/MerchantService.kt similarity index 70% rename from fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/service/MerchantService.kt rename to merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/service/MerchantService.kt index f68a441..a38776c 100644 --- a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/service/MerchantService.kt +++ b/merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/service/MerchantService.kt @@ -1,9 +1,9 @@ -package space.shefer.receipt.fnssdk.service +package space.shefer.receipt.merchants.service import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service -import space.shefer.receipt.fnssdk.primainform.MerchantSuggestion -import space.shefer.receipt.fnssdk.webclient.PrimaInformWebClient +import space.shefer.receipt.merchants.primainform.MerchantSuggestion +import space.shefer.receipt.merchants.webclient.PrimaInformWebClient @Service class MerchantService { diff --git a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/webclient/PrimaInformWebClient.kt b/merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/webclient/PrimaInformWebClient.kt similarity index 83% rename from fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/webclient/PrimaInformWebClient.kt rename to merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/webclient/PrimaInformWebClient.kt index f660800..a519ee4 100644 --- a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/webclient/PrimaInformWebClient.kt +++ b/merchants-resolver/src/main/kotlin/space/shefer/receipt/merchants/webclient/PrimaInformWebClient.kt @@ -1,10 +1,10 @@ -package space.shefer.receipt.fnssdk.webclient +package space.shefer.receipt.merchants.webclient import org.springframework.http.HttpEntity import org.springframework.http.HttpMethod import org.springframework.stereotype.Component import org.springframework.web.client.RestTemplate -import space.shefer.receipt.fnssdk.primainform.MerchantSuggestions +import space.shefer.receipt.merchants.primainform.MerchantSuggestions import java.net.URI @Component diff --git a/fns-sdk/src/test/kotlin/space/shefer/receipt/fnssdk/service/MerchantDtoTest.kt b/merchants-resolver/src/test/kotlin/space/shefer/receipt/merchants/service/MerchantDtoTest.kt similarity index 92% rename from fns-sdk/src/test/kotlin/space/shefer/receipt/fnssdk/service/MerchantDtoTest.kt rename to merchants-resolver/src/test/kotlin/space/shefer/receipt/merchants/service/MerchantDtoTest.kt index c2e2472..36d0e9b 100644 --- a/fns-sdk/src/test/kotlin/space/shefer/receipt/fnssdk/service/MerchantDtoTest.kt +++ b/merchants-resolver/src/test/kotlin/space/shefer/receipt/merchants/service/MerchantDtoTest.kt @@ -1,9 +1,9 @@ -package space.shefer.receipt.fnssdk.service +package space.shefer.receipt.merchants.service import com.fasterxml.jackson.databind.ObjectMapper import junit.framework.TestCase.assertEquals import org.junit.Test -import space.shefer.receipt.fnssdk.primainform.MerchantSuggestions +import space.shefer.receipt.merchants.primainform.MerchantSuggestions internal class MerchantDtoTest { diff --git a/settings.gradle b/settings.gradle index 6893793..2be7be7 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,6 +5,7 @@ include 'core' include 'core-dto' include 'importer-email' include 'fns-sdk' +include 'merchants-resolver' include 'rest-api' include 'rest-api-dto' include 'storage-filesystem' From e5e46799cabdd439b2cc84f398dc6748d67f86e5 Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Fri, 12 Feb 2021 18:28:22 +0300 Subject: [PATCH 23/30] Remove resundant components from `fns-sdk` --- .../receipt/fnssdk/excepion/FnsException.kt | 13 -- .../receipt/fnssdk/service/FnsService.kt | 45 ------ .../fnssdk/webclient/FnsReceiptWebClient.kt | 130 ------------------ 3 files changed, 188 deletions(-) delete mode 100644 fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/excepion/FnsException.kt delete mode 100644 fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/service/FnsService.kt delete mode 100644 fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/webclient/FnsReceiptWebClient.kt diff --git a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/excepion/FnsException.kt b/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/excepion/FnsException.kt deleted file mode 100644 index aa30dab..0000000 --- a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/excepion/FnsException.kt +++ /dev/null @@ -1,13 +0,0 @@ -package space.shefer.receipt.fnssdk.excepion - -import org.springframework.http.HttpStatus -import org.springframework.web.bind.annotation.ResponseStatus - -open class FnsException(message: String, cause: Throwable? = null) : RuntimeException(message, cause) - -class ReceiptNotFoundException(val fn: String, val fd: String, val fp: String) - : FnsException("fn=$fn, fd=$fd, fp=$fp") - -@ResponseStatus(code = HttpStatus.FORBIDDEN) -class AuthorizationFailedException(login: String, cause: Throwable? = null) - : FnsException("Login with phone $login failed", cause) diff --git a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/service/FnsService.kt b/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/service/FnsService.kt deleted file mode 100644 index 25c046d..0000000 --- a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/service/FnsService.kt +++ /dev/null @@ -1,45 +0,0 @@ -package space.shefer.receipt.fnssdk.service - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.stereotype.Service -import space.shefer.receipt.fnssdk.excepion.AuthorizationFailedException -import space.shefer.receipt.fnssdk.excepion.ReceiptNotFoundException -import space.shefer.receipt.fnssdk.webclient.FnsReceiptWebClient -import java.util.concurrent.TimeUnit - -@Service -class FnsService { - - @Autowired - lateinit var fnsReceiptWebClient: FnsReceiptWebClient - - fun getReceiptExists(fn: String, fd: String, fp: String, time: String, - money: Float, phone: String?, password: String?): String? { - if (fnsReceiptWebClient.getReceiptExists(fn, fd, fp, time, money)) { - for (i in 1..MAX_ATTEMPTS) { - try { - val dataReceipt = if (phone == null || password == null) { - fnsReceiptWebClient.get(fn, fd, fp) - } else { - fnsReceiptWebClient.get(fn, fd, fp, phone, password) - } - - if (dataReceipt != null) { - return dataReceipt - } - } catch (e: AuthorizationFailedException) { - throw e - } catch (e: Exception) { - e.printStackTrace() - } - TimeUnit.SECONDS.sleep(1) - } - } - throw ReceiptNotFoundException(fn, fd, fp) - } - - companion object { - private const val MAX_ATTEMPTS = 10 - } - -} diff --git a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/webclient/FnsReceiptWebClient.kt b/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/webclient/FnsReceiptWebClient.kt deleted file mode 100644 index 6a0ced2..0000000 --- a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/webclient/FnsReceiptWebClient.kt +++ /dev/null @@ -1,130 +0,0 @@ -package space.shefer.receipt.fnssdk.webclient - -import org.springframework.beans.factory.annotation.Value -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatus -import org.springframework.stereotype.Component -import org.springframework.web.client.HttpClientErrorException -import org.springframework.web.client.HttpServerErrorException -import org.springframework.web.client.RestTemplate -import space.shefer.receipt.fnssdk.excepion.AuthorizationFailedException -import java.net.URI -import java.util.* - -@Component -class FnsReceiptWebClient { - - @Value("\${fns.login}") - lateinit var login: String - - @Value("\${fns.password}") - lateinit var password: String - - fun get(fn: String, fd: String, fp: String): String? { - return get(fn, fd, fp, login, password) - } - - fun get(fn: String, fd: String, fp: String, phoneUser: String, passwordUser: String): String? { - login(phoneUser, passwordUser) - val uri = urlGet(fn, fd, fp) - val headers = HttpHeaders() - headers.add("device-id", "") - headers.add("device-os", "") - headers.add("Authorization", getAuthHeader(phoneUser, passwordUser)) - - val responseEntity = RestTemplate().exchange( - URI.create(uri), - HttpMethod.GET, - HttpEntity(headers), - String::class.java - ) - if (responseEntity.statusCode == HttpStatus.OK) { - return responseEntity.body - } - return null - } - - - fun getReceiptExists(fn: String, fd: String, fp: String, time: String, money: Float): Boolean { - val moneyForUrl: Int = (money * 100).toInt() - val uri = "$HOST/v1/ofds/*/inns/*/fss/$fn/operations/1/tickets/$fd?fiscalSign=$fp&date=$time&sum=$moneyForUrl" - val headers = HttpHeaders() - - val responseEntity = try { - RestTemplate().exchange( - URI.create(uri), - HttpMethod.GET, - HttpEntity(headers), - String::class.java - ) - } catch (e: HttpServerErrorException) { - if (e.statusCode == HttpStatus.NOT_ACCEPTABLE) { - return false - } - - throw e - } - - return responseEntity.statusCode == HttpStatus.NO_CONTENT - } - - fun passwordRestore(number: String) { - val headers = HttpHeaders() - headers.add("Content-Type", "application/json; charset=UTF-8") - RestTemplate().exchange( - URI("$HOST/v1/mobile/users/restore"), - HttpMethod.POST, - HttpEntity("""{"phone":"$number"}""", headers), - String::class.java - ) - } - - fun signUp(email: String, name: String, phone: String) { - val headers = HttpHeaders() - headers.add("Content-Type", "application/json; charset=UTF-8") - RestTemplate().exchange( - URI("$HOST/v1/mobile/users/signup"), - HttpMethod.POST, - HttpEntity("""{"email":"$email","name":"$name","phone":"$phone"}""", headers), - String::class.java - ) - } - - fun login(login: String, password: String) { - val headers = HttpHeaders() - headers.add("Content-Type", "application/json; charset=UTF-8") - headers.add("Authorization", getAuthHeader(login, password)) - try { - RestTemplate().exchange( - URI("$HOST/v1/mobile/users/login"), - HttpMethod.GET, - HttpEntity(headers), - String::class.java - ) - } catch (e: HttpClientErrorException.Forbidden) { - throw AuthorizationFailedException(login, e) - } - } - - private fun getAuthHeader(login: String, password: String): String { - val plainCredentials = "$login:$password" - val plainCredentialsBytes = plainCredentials.toByteArray() - val base64CredentialsBytes = Base64.getEncoder().encode(plainCredentialsBytes) - val base64Credentials = String(base64CredentialsBytes) - return "Basic $base64Credentials" - } - - companion object { - private const val HOST = "https://proverkacheka.nalog.ru:9999" - private fun urlGet(fn: String, fd: String, fp: String): String { - return HOST + "/v1/inns/*/kkts/*" + - "/fss/" + fn + - "/tickets/" + fd + - "?fiscalSign=" + fp + - "&sendToEmail=no" - } - - } -} From 0ad48fd90def310565ba0f633124388390db21b2 Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Mon, 15 Feb 2021 16:43:08 +0300 Subject: [PATCH 24/30] Remove ReceiptCreateDto & creation methods --- .../receipt/rest/dto/ReceiptCreateDto.java | 39 ------------------- .../rest/converters/ReceiptMetaConverter.java | 9 ----- .../receipt/rest/service/ReceiptService.java | 31 --------------- .../rest/service/ReceiptServiceTest.java | 29 -------------- 4 files changed, 108 deletions(-) delete mode 100644 rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/ReceiptCreateDto.java diff --git a/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/ReceiptCreateDto.java b/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/ReceiptCreateDto.java deleted file mode 100644 index 2f0e3e1..0000000 --- a/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/ReceiptCreateDto.java +++ /dev/null @@ -1,39 +0,0 @@ -package space.shefer.receipt.rest.dto; - -import com.fasterxml.jackson.annotation.JsonFormat; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import space.shefer.receipt.platform.core.dto.util.DateUtil; - -import java.time.LocalDateTime; -import javax.validation.constraints.Pattern; - -@Data -public class ReceiptCreateDto { - public static final String POSITIVE_EXACTLY_16_DIGIT_NUMBER_REGEX = "^(?!0{0,16}$)[0-9]{16}$"; - public static final String POSITIVE_UPTO_16_DIGIT_NUMBER_REGEX = "^(?!0{0,16}$)[0-9]{0,16}$"; - - @Schema( - description = DateUtil.RECEIPT_DATETIME_DESCRIPTION, - pattern = DateUtil.RECEIPT_DATETIME_REGEX, - example = "20170131T2359" - ) - @JsonFormat( - pattern = DateUtil.RECEIPT_DATETIME_PATTERN) - private LocalDateTime date; - - @Pattern(regexp = POSITIVE_EXACTLY_16_DIGIT_NUMBER_REGEX, - message = "The fiscal number (fn) must a positive number and have a length of 16 characters.") - private String fn; - - @Pattern(regexp = POSITIVE_UPTO_16_DIGIT_NUMBER_REGEX, - message = "The fiscal document (fd) must be a positive number.") - private String fd; - - @Pattern(regexp = POSITIVE_UPTO_16_DIGIT_NUMBER_REGEX, - message = "The fiscal indication (fp) must be a positive number.") - private String fp; - - private Double sum; - -} diff --git a/rest-api/src/main/java/space/shefer/receipt/rest/converters/ReceiptMetaConverter.java b/rest-api/src/main/java/space/shefer/receipt/rest/converters/ReceiptMetaConverter.java index 4d178a0..f6e01d1 100644 --- a/rest-api/src/main/java/space/shefer/receipt/rest/converters/ReceiptMetaConverter.java +++ b/rest-api/src/main/java/space/shefer/receipt/rest/converters/ReceiptMetaConverter.java @@ -2,7 +2,6 @@ import org.apache.commons.lang3.ObjectUtils; import space.shefer.receipt.platform.core.entity.Receipt; -import space.shefer.receipt.rest.dto.ReceiptCreateDto; import space.shefer.receipt.rest.dto.ReceiptMetaDto; public class ReceiptMetaConverter { @@ -23,12 +22,4 @@ public static ReceiptMetaDto toDto(Receipt receipt) { return result; } - public static void map(ReceiptCreateDto receipt, Receipt receiptEntity) { - receiptEntity.setDate(receipt.getDate()); - receiptEntity.setFn(receipt.getFn()); - receiptEntity.setFd(receipt.getFd()); - receiptEntity.setFp(receipt.getFp()); - receiptEntity.setSum(receipt.getSum()); - } - } diff --git a/rest-api/src/main/java/space/shefer/receipt/rest/service/ReceiptService.java b/rest-api/src/main/java/space/shefer/receipt/rest/service/ReceiptService.java index 64e4d3d..0e35b39 100644 --- a/rest-api/src/main/java/space/shefer/receipt/rest/service/ReceiptService.java +++ b/rest-api/src/main/java/space/shefer/receipt/rest/service/ReceiptService.java @@ -9,15 +9,12 @@ import space.shefer.receipt.platform.core.dto.ReceiptStatus; import space.shefer.receipt.platform.core.dto.ReportMetaFilter; import space.shefer.receipt.platform.core.entity.Receipt; -import space.shefer.receipt.platform.core.entity.UserProfile; import space.shefer.receipt.platform.core.repository.ReceiptRepository; import space.shefer.receipt.rest.converters.ReceiptMetaConverter; -import space.shefer.receipt.rest.dto.ReceiptCreateDto; import space.shefer.receipt.rest.dto.ReceiptMetaDto; import javax.annotation.Nullable; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -48,34 +45,6 @@ public List getReceipts(ReportMetaFilter metaFilter) { .collect(Collectors.toList()); } - public Receipt create(ReceiptCreateDto receipt, @Nullable UserProfile userProfile) { - List matchingReceipts = receiptRepository.getReceipts( - ReportMetaFilter.builder() - .fn(receipt.getFn()) - .fd(receipt.getFd()) - .fp(receipt.getFp()) - .dateFrom(receipt.getDate()) - .dateTo(receipt.getDate()) - .sumMax(receipt.getSum()) - .sumMin(receipt.getSum()) - .build() - ); - - Optional matchingReceipt = matchingReceipts.stream() - .filter(r -> Objects.equals(userProfile, r.getUserProfile())) - .findAny(); - - if (matchingReceipt.isPresent()) { - return matchingReceipt.get(); - } - - Receipt entity = new Receipt(); - ReceiptMetaConverter.map(receipt, entity); - entity.setStatus(ReceiptStatus.IDLE); - entity.setUserProfile(userProfile); - return receiptRepository.save(entity); - } - private void setDefaultPlaceIfNull(ReceiptMetaDto i) { if (i.getPlace() == null && !StringUtils.isBlank(defaultPlace)) { i.setPlace(defaultPlace); diff --git a/rest-api/src/test/java/space/shefer/receipt/rest/service/ReceiptServiceTest.java b/rest-api/src/test/java/space/shefer/receipt/rest/service/ReceiptServiceTest.java index ee7a1de..004f023 100644 --- a/rest-api/src/test/java/space/shefer/receipt/rest/service/ReceiptServiceTest.java +++ b/rest-api/src/test/java/space/shefer/receipt/rest/service/ReceiptServiceTest.java @@ -2,13 +2,10 @@ import org.junit.Before; import org.junit.Test; -import org.mockito.ArgumentCaptor; import space.shefer.receipt.platform.core.dto.ReportMetaFilter; import space.shefer.receipt.platform.core.entity.Receipt; -import space.shefer.receipt.platform.core.entity.UserProfile; import space.shefer.receipt.platform.core.repository.ReceiptRepository; import space.shefer.receipt.platform.core.util.DateUtil; -import space.shefer.receipt.rest.dto.ReceiptCreateDto; import java.util.Arrays; @@ -51,32 +48,6 @@ public void getReceipts() { verify(receiptRepository).getReceipts(metaFilter); } - @Test - public void create() { - UserProfile userProfile = new UserProfile(); - userProfile.setId("bcce81c9-cbf3-4216-819d-70b9e37da6e3"); - userProfile.setPassword("aaaaa"); - userProfile.setPhone("+7999999999"); - userProfile.setAccessToken("6b6c0abf-82cc-40fb-8379-30e9d0e72bc7"); - ReceiptCreateDto receipt = new ReceiptCreateDto(); - receipt.setDate(DateUtil.parseReceiptDate("20190725T2313")); - receipt.setFn("1111"); - receipt.setFd("2222"); - receipt.setFp("3333"); - receipt.setSum(100.0); - when(receiptRepository.save(any())).thenReturn(createReceiptWithId("400")); - service.create(receipt, userProfile); - ArgumentCaptor receiptCaptor = ArgumentCaptor.forClass(Receipt.class); - verify(receiptRepository).save(receiptCaptor.capture()); - Receipt actual = receiptCaptor.getValue(); - assertEquals(DateUtil.parseReceiptDate("20190725T2313"), actual.getDate()); - assertEquals("1111", actual.getFn()); - assertEquals("2222", actual.getFd()); - assertEquals("3333", actual.getFp()); - assertEquals(100.0, actual.getSum(), 1e-5); - assertNull(actual.getProvider()); - } - @Test public void trimAddressLine() { assertEquals(ReceiptService.trimAddressLine("----asdasdasdasd312314--"), "asdasdasdasd312314"); From 90e4040cc80fb9c1e65b9a0d4bfffaa97d60d642 Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Mon, 15 Feb 2021 16:43:30 +0300 Subject: [PATCH 25/30] Remove UserPasswordRestoreDto.java --- .../rest/dto/UserPasswordRestoreDto.java | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/UserPasswordRestoreDto.java diff --git a/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/UserPasswordRestoreDto.java b/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/UserPasswordRestoreDto.java deleted file mode 100644 index 5bd5dfd..0000000 --- a/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/UserPasswordRestoreDto.java +++ /dev/null @@ -1,17 +0,0 @@ -package space.shefer.receipt.rest.dto; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -public class UserPasswordRestoreDto { - - @Schema( - required = true, - description = "Phone number", - format = "+79XXXXXXXXX", - example = "+79631234567" - ) - private String phone; - -} From 9e5750736b7d9675443eb4ba48e4fb119976077f Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Mon, 15 Feb 2021 16:47:42 +0300 Subject: [PATCH 26/30] Remove UserLoginDto.java --- .../shefer/receipt/rest/dto/UserLoginDto.java | 22 ------------------- 1 file changed, 22 deletions(-) delete mode 100644 rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/UserLoginDto.java diff --git a/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/UserLoginDto.java b/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/UserLoginDto.java deleted file mode 100644 index d29a786..0000000 --- a/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/UserLoginDto.java +++ /dev/null @@ -1,22 +0,0 @@ -package space.shefer.receipt.rest.dto; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -public class UserLoginDto { - @Schema( - required = true, - description = "Phone number", - format = "+79XXXXXXXXX", - example = "+79631234567" - ) - private String phone; - - @Schema( - required = true, - description = "The sms code", - example = "512890" - ) - private String password; -} From 6e9af3d67df6a46b12a96428715720e3651aeddc Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Mon, 15 Feb 2021 16:47:51 +0300 Subject: [PATCH 27/30] Remove UserSignUpDto.java --- .../receipt/rest/dto/UserSignUpDto.java | 31 ------------------- 1 file changed, 31 deletions(-) delete mode 100644 rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/UserSignUpDto.java diff --git a/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/UserSignUpDto.java b/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/UserSignUpDto.java deleted file mode 100644 index 763a4fd..0000000 --- a/rest-api-dto/src/main/java/space/shefer/receipt/rest/dto/UserSignUpDto.java +++ /dev/null @@ -1,31 +0,0 @@ -package space.shefer.receipt.rest.dto; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -@Data -public class UserSignUpDto { - - @Schema( - required = true, - description = "User email", - example = "john.doe@example.com" - ) - private String email; - - @Schema( - required = true, - description = "User full name", - example = "John Doe" - ) - private String name; - - @Schema( - required = true, - description = "Phone number", - format = "+79XXXXXXXXX", - example = "+79631234567" - ) - private String phone; - -} From 523eaba9dbbf8b6e2384c57ec3570ec69fb7cc7d Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Mon, 15 Feb 2021 17:04:02 +0300 Subject: [PATCH 28/30] Remove FnsSdkConfiguration.kt --- fns-sdk/build.gradle | 5 ++--- .../space/shefer/receipt/fnssdk/config/EnableFnsSdk.kt | 6 ------ .../shefer/receipt/fnssdk/config/FnsSdkConfiguration.kt | 8 -------- 3 files changed, 2 insertions(+), 17 deletions(-) delete mode 100644 fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/config/EnableFnsSdk.kt delete mode 100644 fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/config/FnsSdkConfiguration.kt diff --git a/fns-sdk/build.gradle b/fns-sdk/build.gradle index 9226873..dfca9b3 100644 --- a/fns-sdk/build.gradle +++ b/fns-sdk/build.gradle @@ -7,9 +7,8 @@ dependencies { implementation 'com.fasterxml.jackson.module:jackson-module-kotlin' implementation "org.apache.commons:commons-lang3" implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' - implementation 'org.springframework:spring-web' - implementation 'org.springframework:spring-context-support' testImplementation project(':test-util') - testImplementation "org.springframework.boot:spring-boot-starter-test" + testImplementation "org.junit.jupiter:junit-jupiter" + testImplementation "org.junit.vintage:junit-vintage-engine" } diff --git a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/config/EnableFnsSdk.kt b/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/config/EnableFnsSdk.kt deleted file mode 100644 index 97733bb..0000000 --- a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/config/EnableFnsSdk.kt +++ /dev/null @@ -1,6 +0,0 @@ -package space.shefer.receipt.fnssdk.config - -import org.springframework.context.annotation.Import - -@Import(FnsSdkConfiguration::class) -annotation class EnableFnsSdk diff --git a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/config/FnsSdkConfiguration.kt b/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/config/FnsSdkConfiguration.kt deleted file mode 100644 index b656b29..0000000 --- a/fns-sdk/src/main/kotlin/space/shefer/receipt/fnssdk/config/FnsSdkConfiguration.kt +++ /dev/null @@ -1,8 +0,0 @@ -package space.shefer.receipt.fnssdk.config - -import org.springframework.context.annotation.ComponentScan -import org.springframework.context.annotation.Configuration - -@ComponentScan("space.shefer.receipt.fnssdk") -@Configuration -class FnsSdkConfiguration From 45846347359e1c10261f0808bd283fd87516e544 Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Thu, 25 Feb 2021 16:55:33 +0300 Subject: [PATCH 29/30] Remove unused endpoints and services --- .../core/ReceiptCoreConfiguration.java | 2 - .../rest/controller/ReceiptController.java | 36 ------- .../rest/controller/ReportController.java | 36 ------- .../rest/controller/TgbotController.java | 47 -------- .../receipt/rest/service/ItemService.java | 29 ----- .../receipt/rest/service/ReceiptService.java | 101 ------------------ .../rest/controller/ReportControllerTest.java | 56 ---------- .../rest/controller/TgbotControllerTest.java | 76 ------------- .../rest/service/ReceiptServiceTest.java | 68 ------------ 9 files changed, 451 deletions(-) delete mode 100644 rest-api/src/main/java/space/shefer/receipt/rest/controller/ReceiptController.java delete mode 100644 rest-api/src/main/java/space/shefer/receipt/rest/controller/ReportController.java delete mode 100644 rest-api/src/main/java/space/shefer/receipt/rest/controller/TgbotController.java delete mode 100644 rest-api/src/main/java/space/shefer/receipt/rest/service/ItemService.java delete mode 100644 rest-api/src/main/java/space/shefer/receipt/rest/service/ReceiptService.java delete mode 100644 rest-api/src/test/java/space/shefer/receipt/rest/controller/ReportControllerTest.java delete mode 100644 rest-api/src/test/java/space/shefer/receipt/rest/controller/TgbotControllerTest.java delete mode 100644 rest-api/src/test/java/space/shefer/receipt/rest/service/ReceiptServiceTest.java diff --git a/core/src/main/java/space/shefer/receipt/platform/core/ReceiptCoreConfiguration.java b/core/src/main/java/space/shefer/receipt/platform/core/ReceiptCoreConfiguration.java index 731fa24..7d73e4c 100644 --- a/core/src/main/java/space/shefer/receipt/platform/core/ReceiptCoreConfiguration.java +++ b/core/src/main/java/space/shefer/receipt/platform/core/ReceiptCoreConfiguration.java @@ -5,9 +5,7 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; -import space.shefer.receipt.fnssdk.config.EnableFnsSdk; -@EnableFnsSdk @ComponentScan @EnableJpaRepositories @EnableJpaAuditing diff --git a/rest-api/src/main/java/space/shefer/receipt/rest/controller/ReceiptController.java b/rest-api/src/main/java/space/shefer/receipt/rest/controller/ReceiptController.java deleted file mode 100644 index 1db098f..0000000 --- a/rest-api/src/main/java/space/shefer/receipt/rest/controller/ReceiptController.java +++ /dev/null @@ -1,36 +0,0 @@ -package space.shefer.receipt.rest.controller; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import space.shefer.receipt.rest.service.ReceiptService; - -@Tag(name = "Receipts management") -@RestController -@RequiredArgsConstructor -public class ReceiptController { - - private final ReceiptService receiptService; - - @Operation( - description = "Allows remove receipt if it is stuck in loading", - responses = { - @ApiResponse(responseCode = "200", description = "Receipt has been deleted or not found"), - @ApiResponse(responseCode = "400", description = "Receipt already loaded") - } - ) - @RequestMapping(value = "/delete", method = RequestMethod.DELETE) - public void delete( - @Parameter(description = "Receipt identifier", required = true) - @RequestParam long id - ) { - receiptService.deleteReceipt(id); - } - -} diff --git a/rest-api/src/main/java/space/shefer/receipt/rest/controller/ReportController.java b/rest-api/src/main/java/space/shefer/receipt/rest/controller/ReportController.java deleted file mode 100644 index 6f3061b..0000000 --- a/rest-api/src/main/java/space/shefer/receipt/rest/controller/ReportController.java +++ /dev/null @@ -1,36 +0,0 @@ -package space.shefer.receipt.rest.controller; - -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; -import space.shefer.receipt.platform.core.dto.ReportItemFilter; -import space.shefer.receipt.platform.core.dto.ReportMetaFilter; -import space.shefer.receipt.rest.dto.ReceiptItemDto; -import space.shefer.receipt.rest.dto.ReceiptMetaDto; -import space.shefer.receipt.rest.service.ItemService; -import space.shefer.receipt.rest.service.ReceiptService; - -import java.util.List; - -@Tag(name = "Data requests") -@RestController -@RequiredArgsConstructor -public class ReportController { - - private final ReceiptService receiptService; - private final ItemService itemService; - - @RequestMapping(value = "/receipts", method = RequestMethod.PUT) - public List receipts(@RequestBody ReportMetaFilter query) { - return receiptService.getReceipts(query); - } - - @RequestMapping(value = "/items", method = RequestMethod.PUT) - public List items(@RequestBody ReportItemFilter query) { - return itemService.getItems(query); - } - -} diff --git a/rest-api/src/main/java/space/shefer/receipt/rest/controller/TgbotController.java b/rest-api/src/main/java/space/shefer/receipt/rest/controller/TgbotController.java deleted file mode 100644 index 8aba871..0000000 --- a/rest-api/src/main/java/space/shefer/receipt/rest/controller/TgbotController.java +++ /dev/null @@ -1,47 +0,0 @@ -package space.shefer.receipt.rest.controller; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.RequiredArgsConstructor; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; -import space.shefer.receipt.fnssdk.dto.FnsAppReceiptDto; -import space.shefer.receipt.platform.core.dto.ReceiptProvider; -import space.shefer.receipt.platform.core.entity.Receipt; -import space.shefer.receipt.platform.core.service.FnsReceiptService; -import space.shefer.receipt.rest.dto.TgbotCreateBody; - -@Tag(name = "Telegram bot") -@RestController -@RequestMapping("tgbot") -@RequiredArgsConstructor -public class TgbotController { - - private final FnsReceiptService receiptService; - - @Operation( - description = "Submit receipt from telegram-bot", - responses = @ApiResponse( - responseCode = "200", - description = "Receipt successfully submitted", - content = @Content(schema = @Schema( - description = "The id of receipt which was created", - example = "135" - )) - ) - ) - @RequestMapping(value = "/create", method = RequestMethod.POST, produces = MediaType.TEXT_PLAIN_VALUE) - public String create(@RequestBody TgbotCreateBody body) { - FnsAppReceiptDto fnsAppReceiptDto = FnsAppReceiptDto.fromString(body.getReceiptJson()); - return receiptService - .update(fnsAppReceiptDto, new Receipt(), ReceiptProvider.TGBOT_NALOG.name()) - .getId(); - } - -} diff --git a/rest-api/src/main/java/space/shefer/receipt/rest/service/ItemService.java b/rest-api/src/main/java/space/shefer/receipt/rest/service/ItemService.java deleted file mode 100644 index 9c817f4..0000000 --- a/rest-api/src/main/java/space/shefer/receipt/rest/service/ItemService.java +++ /dev/null @@ -1,29 +0,0 @@ -package space.shefer.receipt.rest.service; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import space.shefer.receipt.platform.core.dto.ReportItemFilter; -import space.shefer.receipt.platform.core.entity.Item; -import space.shefer.receipt.platform.core.repository.ItemRepository; -import space.shefer.receipt.rest.converters.ReceiptItemConverter; -import space.shefer.receipt.rest.dto.ReceiptItemDto; - -import java.util.List; -import java.util.stream.Collectors; - -@Service -public class ItemService { - - @Autowired - public ItemService(ItemRepository itemRepository) { - this.itemRepository = itemRepository; - } - - private final ItemRepository itemRepository; - - public List getItems(ReportItemFilter itemFilter) { - List receipts = itemRepository.getItems(itemFilter); - return receipts.stream().map(ReceiptItemConverter::toDto).collect(Collectors.toList()); - } - -} diff --git a/rest-api/src/main/java/space/shefer/receipt/rest/service/ReceiptService.java b/rest-api/src/main/java/space/shefer/receipt/rest/service/ReceiptService.java deleted file mode 100644 index 0e35b39..0000000 --- a/rest-api/src/main/java/space/shefer/receipt/rest/service/ReceiptService.java +++ /dev/null @@ -1,101 +0,0 @@ -package space.shefer.receipt.rest.service; - -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Service; -import org.springframework.web.server.ResponseStatusException; -import space.shefer.receipt.platform.core.dto.ReceiptStatus; -import space.shefer.receipt.platform.core.dto.ReportMetaFilter; -import space.shefer.receipt.platform.core.entity.Receipt; -import space.shefer.receipt.platform.core.repository.ReceiptRepository; -import space.shefer.receipt.rest.converters.ReceiptMetaConverter; -import space.shefer.receipt.rest.dto.ReceiptMetaDto; - -import javax.annotation.Nullable; -import java.util.List; -import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -@Service -public class ReceiptService { - - @Value(value = "${receipt.place.default}") - private String defaultPlace; - - private final ReceiptRepository receiptRepository; - private final MerchantLogoService merchantLogoService; - private static final Pattern pattern = Pattern.compile("[а-яА-ЯёЁa-zA-Z0-9]"); - - @Autowired - public ReceiptService(ReceiptRepository receiptRepository, MerchantLogoService merchantLogoService) { - this.receiptRepository = receiptRepository; - this.merchantLogoService = merchantLogoService; - } - - public List getReceipts(ReportMetaFilter metaFilter) { - List receipts = receiptRepository.getReceipts(metaFilter); - return receipts.stream().map(ReceiptMetaConverter::toDto) - .peek(this::setDefaultPlaceIfNull) - .peek(receipt -> receipt.setMerchantLogoUrl(merchantLogoService.getUrlForImagePlace(receipt.getPlace()))) - .peek(receipt -> receipt.setMerchantPlaceAddress(trimAddressLine(receipt.getMerchantPlaceAddress()))) - .collect(Collectors.toList()); - } - - private void setDefaultPlaceIfNull(ReceiptMetaDto i) { - if (i.getPlace() == null && !StringUtils.isBlank(defaultPlace)) { - i.setPlace(defaultPlace); - } - } - - public void deleteReceipt(long id) { - Optional receipt = receiptRepository.findById(id); - if (receipt.isPresent()) { - if (receipt.get().getStatus() == ReceiptStatus.LOADED) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Receipt is already loaded"); - } - receiptRepository.deleteById(id); - } - } - - @Nullable - public static String trimAddressLine(@Nullable String address) { - if (address == null) { - return null; - } - StringBuilder stringBuilder = new StringBuilder(address); - int firstPosition = 0; - for (int i = 0; i < stringBuilder.length(); i++) { - char c = address.charAt(i); - Matcher matcher = pattern.matcher(Character.toString(c)); - if (matcher.matches()) { - firstPosition = i; - break; - } - - } - int lastPosition = 0; - for (int i = stringBuilder.length() - 1; i >= 0; i--) { - char c = address.charAt(i); - Matcher matcher = pattern.matcher(Character.toString(c)); - if (matcher.matches()) { - lastPosition = i + 1; - break; - } - - } - if (lastPosition == 0 && firstPosition == 0) { - return ""; - } - if (lastPosition == firstPosition) { - return address; - } - else { - return address.substring(firstPosition, lastPosition); - } - } - -} diff --git a/rest-api/src/test/java/space/shefer/receipt/rest/controller/ReportControllerTest.java b/rest-api/src/test/java/space/shefer/receipt/rest/controller/ReportControllerTest.java deleted file mode 100644 index 3d04ff7..0000000 --- a/rest-api/src/test/java/space/shefer/receipt/rest/controller/ReportControllerTest.java +++ /dev/null @@ -1,56 +0,0 @@ -package space.shefer.receipt.rest.controller; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import space.shefer.receipt.platform.core.dto.ReportMetaFilter; -import space.shefer.receipt.platform.core.util.DateUtil; -import space.shefer.receipt.rest.service.ItemService; -import space.shefer.receipt.rest.service.ReceiptService; -import space.shefer.receipt.tests.util.ResourceUtil; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -public class ReportControllerTest { - - private MockMvc mockMvc; - private ReportController controller; - private ReceiptService service; - - @Before - public void setUp() { - service = mock(ReceiptService.class); - controller = spy(new ReportController(service, mock(ItemService.class))); - mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); - } - - @SuppressWarnings("ConstantConditions") - @Test - public void testReceipts() throws Exception { - String body = ResourceUtil.getResourceAsString("/controller/ReportControllerTest_testReceipts.json", getClass()); - mockMvc.perform(put("/receipts").content(body) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()); - ArgumentCaptor filterCaptor= ArgumentCaptor.forClass(ReportMetaFilter.class); - verify(service, times(1)).getReceipts(filterCaptor.capture()); - ReportMetaFilter metaFilter = filterCaptor.getValue(); - assertEquals(DateUtil.parseReceiptDate("20190801T1032"), metaFilter.getDateFrom()); - assertEquals(DateUtil.parseReceiptDate("20190802T1345"), metaFilter.getDateTo()); - assertEquals(362954, metaFilter.getSumMin(), 1e-5); - assertEquals(123629, metaFilter.getSumMax(), 1e-5); - assertEquals("936933", metaFilter.getFn()); - assertEquals("832555", metaFilter.getFd()); - assertEquals("535594", metaFilter.getFp()); - assertEquals("someplace", metaFilter.getPlace()); - } - -} diff --git a/rest-api/src/test/java/space/shefer/receipt/rest/controller/TgbotControllerTest.java b/rest-api/src/test/java/space/shefer/receipt/rest/controller/TgbotControllerTest.java deleted file mode 100644 index 5ed6747..0000000 --- a/rest-api/src/test/java/space/shefer/receipt/rest/controller/TgbotControllerTest.java +++ /dev/null @@ -1,76 +0,0 @@ -package space.shefer.receipt.rest.controller; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import space.shefer.receipt.fnssdk.dto.FnsReceiptDto; -import space.shefer.receipt.platform.core.dto.ReceiptProvider; -import space.shefer.receipt.platform.core.entity.Receipt; -import space.shefer.receipt.platform.core.service.FnsReceiptService; -import space.shefer.receipt.rest.dto.TgbotCreateBody; -import space.shefer.receipt.tests.util.ResourceUtil; - -import java.time.LocalDateTime; - -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -public class TgbotControllerTest { - - private MockMvc mockMvc; - private TgbotController controller; - private FnsReceiptService service; - - @Before - public void setUp() { - service = mock(FnsReceiptService.class); - controller = spy(new TgbotController(service)); - mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); - } - - @Test - public void testReceipts() throws Exception { - String receiptJson = ResourceUtil.getResourceAsString("/controller/TgbotControllerTest_testReceipts.json", getClass()); - TgbotCreateBody body = new TgbotCreateBody(); - body.setUserId("123"); - body.setReceiptJson(receiptJson); - String bodyString = new ObjectMapper().writeValueAsString(body); - - doAnswer(__ -> { - Receipt receipt = new Receipt(); - receipt.setId("807"); - return receipt; - }).when(service).update(any(), any(), anyString()); - - mockMvc - .perform(post("/tgbot/create") - .content(bodyString) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(content().string("807")) - .andExpect(status().isOk()); - - ArgumentCaptor filterCaptor = ArgumentCaptor.forClass(FnsReceiptDto.class); - verify(service).update(filterCaptor.capture(), any(), eq(ReceiptProvider.TGBOT_NALOG.name())); - - FnsReceiptDto receipt = filterCaptor.getValue(); - assertEquals(LocalDateTime.of(2020, 2, 29, 16, 51), receipt.getDateTime()); - assertEquals(47900, receipt.getTotalSum()); - assertEquals("9289000100408074", receipt.getFiscalDriveNumber()); - // TODO check other fields - - } - -} diff --git a/rest-api/src/test/java/space/shefer/receipt/rest/service/ReceiptServiceTest.java b/rest-api/src/test/java/space/shefer/receipt/rest/service/ReceiptServiceTest.java deleted file mode 100644 index 004f023..0000000 --- a/rest-api/src/test/java/space/shefer/receipt/rest/service/ReceiptServiceTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package space.shefer.receipt.rest.service; - -import org.junit.Before; -import org.junit.Test; -import space.shefer.receipt.platform.core.dto.ReportMetaFilter; -import space.shefer.receipt.platform.core.entity.Receipt; -import space.shefer.receipt.platform.core.repository.ReceiptRepository; -import space.shefer.receipt.platform.core.util.DateUtil; - -import java.util.Arrays; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class ReceiptServiceTest { - - private ReceiptService service; - private ReceiptRepository receiptRepository; - - @Before - public void setUp() { - receiptRepository = mock(ReceiptRepository.class); - MerchantLogoService merchantLogoService = mock(MerchantLogoService.class); - service = spy(new ReceiptService(receiptRepository, merchantLogoService)); - } - - @Test - public void getReceipts() { - ReportMetaFilter metaFilter = new ReportMetaFilter(); - metaFilter.setDateFrom(DateUtil.parseReceiptDate("20190725T2313")); - metaFilter.setDateTo(DateUtil.parseReceiptDate("20190807T0815")); - metaFilter.setFn("1111"); - metaFilter.setFd("2222"); - metaFilter.setFp("3333"); - metaFilter.setSumMin(100.0); - metaFilter.setSumMax(800.0); - when(receiptRepository.getReceipts(any())) - .thenReturn(Arrays.asList( - createReceiptWithId("1"), - createReceiptWithId("2") - )); - service.getReceipts(metaFilter); - verify(receiptRepository).getReceipts(metaFilter); - } - - @Test - public void trimAddressLine() { - assertEquals(ReceiptService.trimAddressLine("----asdasdasdasd312314--"), "asdasdasdasd312314"); - assertEquals(ReceiptService.trimAddressLine("фы---!вфыв__---__---__--____---"), "фы---!вфыв"); - assertNull(ReceiptService.trimAddressLine(null)); - assertEquals(ReceiptService.trimAddressLine("-----7----"), "7"); - assertEquals(ReceiptService.trimAddressLine("asdad312312rfa"), "asdad312312rfa"); - assertEquals(ReceiptService.trimAddressLine(""), ""); - assertEquals(ReceiptService.trimAddressLine("----!#@#$!____--"), ""); - } - - private Receipt createReceiptWithId(String id){ - Receipt receipt = new Receipt(); - receipt.setId(id); - return receipt; - } - -} From 8ec3274ec591e75fbcebe246344ecbf1c5fc23ac Mon Sep 17 00:00:00 2001 From: Vladimir Shefer Date: Sun, 17 Oct 2021 14:29:35 +0300 Subject: [PATCH 30/30] Dirty commit --- .gitignore | 2 + deploy/elasticsearch/docker-compose.yml | 37 ++++++++ rest-api-2/README.md | 12 +++ rest-api-2/build.gradle | 22 +++++ .../shefer/receipt/rest/RestApplication.java | 18 ++++ .../rest/controller/HealthController.java | 32 +++++++ .../resources/config/application.properties | 2 + .../receipt/rest/RestApplicationTest.java | 14 +++ .../src/test/resources/application.properties | 16 ++++ .../resources/controller/BadJSONRequests.txt | 95 +++++++++++++++++++ .../ReceiptCreateControllerTest_create.json | 7 ++ .../ReportControllerTest_testReceipts.json | 10 ++ .../TgbotControllerTest_testReceipts.json | 75 +++++++++++++++ 13 files changed, 342 insertions(+) create mode 100644 deploy/elasticsearch/docker-compose.yml create mode 100644 rest-api-2/README.md create mode 100644 rest-api-2/build.gradle create mode 100644 rest-api-2/src/main/java/space/shefer/receipt/rest/RestApplication.java create mode 100644 rest-api-2/src/main/java/space/shefer/receipt/rest/controller/HealthController.java create mode 100644 rest-api-2/src/main/resources/config/application.properties create mode 100644 rest-api-2/src/test/java/space/shefer/receipt/rest/RestApplicationTest.java create mode 100644 rest-api-2/src/test/resources/application.properties create mode 100644 rest-api-2/src/test/resources/controller/BadJSONRequests.txt create mode 100644 rest-api-2/src/test/resources/controller/ReceiptCreateControllerTest_create.json create mode 100644 rest-api-2/src/test/resources/controller/ReportControllerTest_testReceipts.json create mode 100644 rest-api-2/src/test/resources/controller/TgbotControllerTest_testReceipts.json diff --git a/.gitignore b/.gitignore index b759032..986d9b3 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,5 @@ gradlew.bat ## Lombok plugin lombok.config + +workdir diff --git a/deploy/elasticsearch/docker-compose.yml b/deploy/elasticsearch/docker-compose.yml new file mode 100644 index 0000000..caeb8fa --- /dev/null +++ b/deploy/elasticsearch/docker-compose.yml @@ -0,0 +1,37 @@ +version: '3' + +services: + elasticsearch: + image: elasticsearch:7.10.1 + environment: + #- cluster.name=docker-cluster + - bootstrap.memory_lock=true + - transport.host=127.0.0.1 + - http.host=0.0.0.0 + - "ES_JAVA_OPTS=-Xms512m -Xmx512m" + ulimits: + memlock: + soft: -1 + hard: -1 + ports: + - "9200:9200" + volumes: + - elasticsearch_data:/usr/share/elasticsearch + networks: + - elastic + kibana: + image: kibana:7.10.1 + ports: + - "5601:5601" + networks: + - elastic + depends_on: + - elasticsearch + +volumes: + elasticsearch_data: + driver: local + +networks: + elastic: + driver: bridge diff --git a/rest-api-2/README.md b/rest-api-2/README.md new file mode 100644 index 0000000..b826cdf --- /dev/null +++ b/rest-api-2/README.md @@ -0,0 +1,12 @@ +# rest-api + +## Description + +Public available at receipt.shefer.space/api + +#Technologies + +- Java +- Spring + - Web + - Data diff --git a/rest-api-2/build.gradle b/rest-api-2/build.gradle new file mode 100644 index 0000000..7b4cf6e --- /dev/null +++ b/rest-api-2/build.gradle @@ -0,0 +1,22 @@ +plugins { + id "io.freefair.lombok" + id 'org.springframework.boot' +} + +dependencies { + implementation project(":storage-filesystem") + + implementation 'com.google.code.findbugs:jsr305' + implementation 'commons-codec:commons-codec' + implementation 'org.apache.commons:commons-lang3' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-actuator' + implementation 'org.springframework:spring-context-support' + implementation 'org.projectlombok:lombok' + implementation 'org.springdoc:springdoc-openapi-ui' + + testImplementation project(':test-util') + + testImplementation "com.h2database:h2" + testImplementation "org.springframework.boot:spring-boot-starter-test" +} diff --git a/rest-api-2/src/main/java/space/shefer/receipt/rest/RestApplication.java b/rest-api-2/src/main/java/space/shefer/receipt/rest/RestApplication.java new file mode 100644 index 0000000..f946254 --- /dev/null +++ b/rest-api-2/src/main/java/space/shefer/receipt/rest/RestApplication.java @@ -0,0 +1,18 @@ +package space.shefer.receipt.rest; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.info.Contact; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.info.License; +import io.swagger.v3.oas.annotations.servers.Server; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Import; +import space.shefer.receipt.platform.core.ReceiptCoreConfiguration; + +@SpringBootApplication +public class RestApplication { + public static void main(String[] args) { + SpringApplication.run(RestApplication.class, args); + } +} diff --git a/rest-api-2/src/main/java/space/shefer/receipt/rest/controller/HealthController.java b/rest-api-2/src/main/java/space/shefer/receipt/rest/controller/HealthController.java new file mode 100644 index 0000000..35d3068 --- /dev/null +++ b/rest-api-2/src/main/java/space/shefer/receipt/rest/controller/HealthController.java @@ -0,0 +1,32 @@ +package space.shefer.receipt.rest.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "API health checks") +@RestController +public class HealthController { + + @Operation( + description = "Health check method. Returns 'pong' string.", + responses = @ApiResponse( + responseCode = "200", + description = "Rest API is up", + content = @Content(schema = @Schema( + description = "The `pong` string" + )) + ) + ) + @RequestMapping(value = "/ping", method = RequestMethod.GET, produces = MediaType.TEXT_PLAIN_VALUE) + public String ping() { + return "pong"; + } + +} diff --git a/rest-api-2/src/main/resources/config/application.properties b/rest-api-2/src/main/resources/config/application.properties new file mode 100644 index 0000000..d883cd6 --- /dev/null +++ b/rest-api-2/src/main/resources/config/application.properties @@ -0,0 +1,2 @@ +springdoc.api-docs.path=/documentation +springdoc.swagger-ui.path=/documentation/view diff --git a/rest-api-2/src/test/java/space/shefer/receipt/rest/RestApplicationTest.java b/rest-api-2/src/test/java/space/shefer/receipt/rest/RestApplicationTest.java new file mode 100644 index 0000000..1b08481 --- /dev/null +++ b/rest-api-2/src/test/java/space/shefer/receipt/rest/RestApplicationTest.java @@ -0,0 +1,14 @@ +package space.shefer.receipt.rest; + +import org.junit.Test; +import space.shefer.receipt.tests.util.SpringIntegrationTest; + +@SpringIntegrationTest +public class RestApplicationTest { + + @Test + public void contextLoads() { + + } + +} diff --git a/rest-api-2/src/test/resources/application.properties b/rest-api-2/src/test/resources/application.properties new file mode 100644 index 0000000..1698366 --- /dev/null +++ b/rest-api-2/src/test/resources/application.properties @@ -0,0 +1,16 @@ +spring.jpa.show-sql=true +spring.datasource.initialization-mode=always +spring.datasource.sql-script-encoding=UTF-8 +spring.messages.encoding=UTF-8 +server.tomcat.uri-encoding=UTF-8 + +## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties) +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.username=postgres +spring.datasource.password= + +# The SQL dialect makes Hibernate generate better SQL for the chosen database +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect + +# Hibernate ddl auto (create, create-drop, validate, update) +spring.jpa.hibernate.ddl-auto=create-drop \ No newline at end of file diff --git a/rest-api-2/src/test/resources/controller/BadJSONRequests.txt b/rest-api-2/src/test/resources/controller/BadJSONRequests.txt new file mode 100644 index 0000000..0eccc19 --- /dev/null +++ b/rest-api-2/src/test/resources/controller/BadJSONRequests.txt @@ -0,0 +1,95 @@ +{ + "date": "20190801T1032", + "fn": "936933", + "fd": "832555", + "fp": "535594", + "sum": 123629 +} +--- +{ + "date": "20190801T1032", + "fn": "936933123456789012345678", + "fd": "832555", + "fp": "535594", + "sum": 123629 +} +--- +{ + "date": "20190801T1032", + "fn": "-12", + "fd": "832555", + "fp": "535594", + "sum": 123629 +} +--- +{ + "date": "20190801T1032", + "fn": "bad", + "fd": "832555", + "fp": "535594", + "sum": 123629 +} +--- +{ + "date": "20190801T1032", + "fn": "", + "fd": "832555", + "fp": "535594", + "sum": 123629 +} +--- +{ + "date": "20190801T1032", + "fn": "0000000000000000", + "fd": "832555", + "fp": "535594", + "sum": 123629 +} +--- +{ + "date": "20190801T1032", + "fn": "9282000100338973", + "fd": "-832555", + "fp": "535594", + "sum": 123629 +} +--- +{ + "date": "20190801T1032", + "fn": "9282000100338973", + "fd": "bad", + "fp": "535594", + "sum": 123629 +} +--- +{ + "date": "20190801T1032", + "fn": "9282000100338973", + "fd": "", + "fp": "535594", + "sum": 123629 +} +--- +{ + "date": "20190801T1032", + "fn": "9282000100338973", + "fd": "832555", + "fp": "-535594", + "sum": 123629 +} +--- +{ + "date": "20190801T1032", + "fn": "9282000100338973", + "fd": "832555", + "fp": "bad", + "sum": 123629 +} +--- +{ + "date": "20190801T1032", + "fn": "9282000100338973", + "fd": "832555", + "fp": "", + "sum": 123629 +} diff --git a/rest-api-2/src/test/resources/controller/ReceiptCreateControllerTest_create.json b/rest-api-2/src/test/resources/controller/ReceiptCreateControllerTest_create.json new file mode 100644 index 0000000..fd0ec6e --- /dev/null +++ b/rest-api-2/src/test/resources/controller/ReceiptCreateControllerTest_create.json @@ -0,0 +1,7 @@ +{ + "date": "20190801T1032", + "fn": "9282000100338973", + "fd": "832555", + "fp": "535594", + "sum": 123629 +} diff --git a/rest-api-2/src/test/resources/controller/ReportControllerTest_testReceipts.json b/rest-api-2/src/test/resources/controller/ReportControllerTest_testReceipts.json new file mode 100644 index 0000000..16f70b8 --- /dev/null +++ b/rest-api-2/src/test/resources/controller/ReportControllerTest_testReceipts.json @@ -0,0 +1,10 @@ +{ + "dateFrom": "20190801T1032", + "dateTo": "20190802T1345", + "sumMin": 362954, + "sumMax": 123629, + "fn": "936933", + "fd": "832555", + "fp": "535594", + "place": "someplace" +} \ No newline at end of file diff --git a/rest-api-2/src/test/resources/controller/TgbotControllerTest_testReceipts.json b/rest-api-2/src/test/resources/controller/TgbotControllerTest_testReceipts.json new file mode 100644 index 0000000..0ae236e --- /dev/null +++ b/rest-api-2/src/test/resources/controller/TgbotControllerTest_testReceipts.json @@ -0,0 +1,75 @@ +{ + "cashTotalSum": 47900, + "dateTime": 1582995060, + "discount": null, + "discountSum": null, + "ecashTotalSum": 0, + "fiscalDocumentNumber": 94083, + "fiscalDriveNumber": "9289000100408074", + "fiscalSign": 4176683349, + "items": [ + { + "modifiers": null, + "name": "3492122 Тарелка КРУГЛЫЙ ГОД 12шт", + "nds0": null, + "nds10": null, + "nds18": null, + "ndsCalculated10": null, + "ndsCalculated18": null, + "ndsNo": null, + "price": 2749, + "quantity": 4.0, + "sum": 10996, + "storno": false + }, + { + "modifiers": null, + "name": "*3499881 Бокал PASABAHCE 2х445мл", + "nds0": null, + "nds10": null, + "nds18": null, + "ndsCalculated10": null, + "ndsCalculated18": null, + "ndsNo": null, + "price": 19999, + "quantity": 1.0, + "sum": 19999, + "storno": false + }, + { + "modifiers": null, + "name": "3689022 Органайзер IDEA 290х130х170мм", + "nds0": null, + "nds10": null, + "nds18": null, + "ndsCalculated10": null, + "ndsCalculated18": null, + "ndsNo": null, + "price": 16999, + "quantity": 1.0, + "sum": 16999, + "storno": false + } + ], + "kktNumber": null, + "kktRegId": "0000113876039230 ", + "markup": null, + "markupSum": null, + "modifiers": null, + "nds0": null, + "nds10": null, + "nds18": null, + "ndsCalculated10": null, + "ndsCalculated18": null, + "ndsNo": null, + "operationType": 1, + "operator": "Кассир-продавец Геворгиз Людмила Анатольевна", + "requestNumber": 89, + "retailPlaceAddress": null, + "shiftNumber": 312, + "stornoItems": null, + "taxationType": 0, + "totalSum": 47900, + "user": null, + "userInn": "7728029110" +}