diff --git a/prototype/src/main/java/org/hso/ecommerce/controller/cronjob/CronjobController.java b/prototype/src/main/java/org/hso/ecommerce/controller/cronjob/CronjobController.java index 815565c..64e1eaa 100644 --- a/prototype/src/main/java/org/hso/ecommerce/controller/cronjob/CronjobController.java +++ b/prototype/src/main/java/org/hso/ecommerce/controller/cronjob/CronjobController.java @@ -1,18 +1,6 @@ package org.hso.ecommerce.controller.cronjob; -import org.hso.ecommerce.action.booking.CreateBookingAction; -import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction; -import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction.ArticleIdentifier; -import org.hso.ecommerce.action.cronjob.ReorderAction; -import org.hso.ecommerce.action.cronjob.UpdateOffersAction; -import org.hso.ecommerce.entities.booking.Booking; -import org.hso.ecommerce.entities.booking.BookingAccountEntry; -import org.hso.ecommerce.entities.booking.BookingReason; import org.hso.ecommerce.entities.cron.BackgroundJob; -import org.hso.ecommerce.entities.shop.Article; -import org.hso.ecommerce.entities.supplier.ArticleOffer; -import org.hso.ecommerce.entities.supplier.Supplier; -import org.hso.ecommerce.entities.supplier.SupplierOrder; import org.hso.ecommerce.repos.booking.BookingAccountEntryRepository; import org.hso.ecommerce.repos.booking.BookingRepository; import org.hso.ecommerce.repos.cronjob.BackgroundJobRepository; @@ -38,197 +26,6 @@ import java.sql.Timestamp; import java.util.*; import java.util.Map.Entry; -interface ICronjob { - /** - * Calculate the earliest cronjob execution time that happens after the given reference time. - * - * @param reference Position in time to start searching. The implementor is allowed to modify the reference time. - * @return A new Calendar instance (or the same) containing the time for next execution. - */ - Calendar nextExecution(Calendar reference); - - /** - * Calculate the latest cronjob execution time that happens before or exactly at the given refernce time. - * - * @param reference Position in time to start searching. The implementor is allowed to modify the reference time. - * @return A new Calendar instance (or the same) containing the time of the last execution. - */ - Calendar previousExecution(Calendar reference); - - /** - * Execute this cronjob. - * - * @param time The point in time this execution was scheduled. In case of a missed cronjob, the actual time of - * this call might be much later. - * @param controller Back-reference that allows to use repositories. - */ - void executeAt(Calendar time, CronjobController controller); - - /** - * Get a name for this cronjob, that can be presented to the user in the frontend. - * - * @return A german name of this cronjob. - */ - String getDisplayName(); -} - -@Component -class Reorder implements ICronjob { - @Override - public String getDisplayName() { - return "Nachbestellung"; - } - - @Override - public Calendar nextExecution(Calendar reference) { - if (reference.get(Calendar.HOUR_OF_DAY) >= 8) { - reference.add(Calendar.DAY_OF_MONTH, 1); - } - reference.set(Calendar.HOUR_OF_DAY, 8); - reference.set(Calendar.MINUTE, 0); - reference.set(Calendar.SECOND, 0); - reference.set(Calendar.MILLISECOND, 0); - return reference; - } - - @Override - public Calendar previousExecution(Calendar reference) { - if (reference.get(Calendar.HOUR_OF_DAY) < 8) { - reference.add(Calendar.DAY_OF_MONTH, -1); - } - reference.set(Calendar.HOUR_OF_DAY, 8); - reference.set(Calendar.MINUTE, 0); - reference.set(Calendar.SECOND, 0); - reference.set(Calendar.MILLISECOND, 0); - return reference; - } - - /** - * Calculates the amount of ordered articles by customers for the given article type in the time between begin and - * end. - * - * @param article The article to search orders for. - * @param begin The start time for the search (included) - * @param end The end time for the search (excluded) - * @return The number of articles that were ordered by customers in the given range. - */ - private Integer getOrderedAmounts(Article article, Calendar begin, Calendar end, CronjobController controller) { - return controller.customerOrderRepository.countOrdersOfArticleInTimespan( - article.id, - new Timestamp(begin.getTimeInMillis()), new Timestamp(end.getTimeInMillis())); - } - - /** - * Calculates the amount of ordered articles by customers for the given article type in the three days before the - * given reference time. The return-array contains 3 fields: Index 0: Orders 72 to 48 hours ago; Index 1: Orders 48 - * to 24 hours ago; Index 2: Orders 24 to 0 hours ago. - * - * @param article The article for which the customer orders are checked. - * @param time The reference time to use for calculation of the last orders. - * @return A 3-element array containing the orders of the last three days. - */ - private Integer[] getOrderedAmounts(Article article, Calendar time, CronjobController controller) { - Calendar oneDayBefore = (Calendar) time.clone(); - oneDayBefore.add(Calendar.DAY_OF_MONTH, -1); - Calendar twoDaysBefore = (Calendar) time.clone(); - twoDaysBefore.add(Calendar.DAY_OF_MONTH, -2); - Calendar threeDaysBefore = (Calendar) time.clone(); - threeDaysBefore.add(Calendar.DAY_OF_MONTH, -3); - - return new Integer[] { // - getOrderedAmounts(article, threeDaysBefore, twoDaysBefore, controller), // - getOrderedAmounts(article, twoDaysBefore, oneDayBefore, controller), // - getOrderedAmounts(article, oneDayBefore, time, controller), // - }; - } - - private HashMap mapArticleOffers(List articleOffers) { - HashMap map = new HashMap<>(); - for (ArticleOffer articleOffer : articleOffers) { - ArticleIdentifier identifier = new ArticleIdentifier(articleOffer.manufacturer, articleOffer.articleNumber); - map.put(identifier, articleOffer); - } - return map; - } - - @Override - public void executeAt(Calendar time, CronjobController controller) { - List suppliers = controller.supplierRepository.findAll(); - ReadSupplierDataAction.Result supplierData = new ReadSupplierDataAction(suppliers).finish(); - - // Save the new offers in the database - List allOffers = controller.articleOfferRepository.findAll(); - allOffers = new UpdateOffersAction(allOffers, supplierData.cheapestOffer).finish(); - controller.articleOfferRepository.saveAll(allOffers); - - HashMap mappedOffers = mapArticleOffers(allOffers); - - // Reorder - List
allArticles = controller.articleRepository.findAll(); - for (Article article : allArticles) { - Integer[] orderedAmounts = getOrderedAmounts(article, time, controller); - - Integer undeliveredReorders = controller.supplierOrderRepository - .countUndeliveredReorders(article.related.articleNumber); - - int amountInStock = controller.warehouseBookingPositionSlotEntryRepository - .getByArticle(article.id) - .stream() - .mapToInt(e -> e.newSumSlot) - .sum(); - - ReorderAction action = new ReorderAction(article, orderedAmounts, - undeliveredReorders, - amountInStock, - supplierData.cheapestOffer, mappedOffers); - SupplierOrder order = action.finish(); - if (order != null) { - controller.supplierOrderRepository.save(order); - - // Create bookings for this order - int netPrice = order.totalPriceNet; - int vatPercent = order.ordered.vatPercent; - int vatAmount = netPrice * vatPercent / 100; - int grossPrice = netPrice + vatAmount; - - // Obligation towards the supplier - BookingAccountEntry mainAccount = controller.bookingAccountEntryRepository.getByMain() - .orElseGet(BookingAccountEntry::newMain); - BookingAccountEntry supplierAccount = controller.bookingAccountEntryRepository - .getBySupplier(order.supplier.id) - .orElseGet(() -> BookingAccountEntry.newSupplier(order.supplier)); - BookingReason obligationReason = new BookingReason(order); - Booking obligationBooking = new CreateBookingAction(mainAccount, - supplierAccount, - obligationReason, - grossPrice).finish(); - controller.bookingRepository.save(obligationBooking); - - // Input Tax - BookingAccountEntry vatAccount = controller.bookingAccountEntryRepository.getByVat() - .orElseGet(BookingAccountEntry::newVat); - mainAccount = controller.bookingAccountEntryRepository.getByMain().get(); - BookingReason inputTaxReason = new BookingReason(order); - Booking inputTaxBooking = new CreateBookingAction(vatAccount, mainAccount, inputTaxReason, vatAmount) - .finish(); - controller.bookingRepository.save(inputTaxBooking); - } - } - } -} - -class ScheduledCronjob { - public final Calendar executionTime; - public final ICronjob cronjob; - public final BackgroundJob model; - - public ScheduledCronjob(Calendar executionTime, ICronjob cronjob, BackgroundJob model) { - this.executionTime = executionTime; - this.cronjob = cronjob; - this.model = model; - } -} - @Component @RequestMapping("intern/cronjobs") class CronjobController { diff --git a/prototype/src/main/java/org/hso/ecommerce/controller/cronjob/ICronjob.java b/prototype/src/main/java/org/hso/ecommerce/controller/cronjob/ICronjob.java new file mode 100644 index 0000000..508bdde --- /dev/null +++ b/prototype/src/main/java/org/hso/ecommerce/controller/cronjob/ICronjob.java @@ -0,0 +1,38 @@ +package org.hso.ecommerce.controller.cronjob; + + +import java.util.Calendar; + +interface ICronjob { + /** + * Calculate the earliest cronjob execution time that happens after the given reference time. + * + * @param reference Position in time to start searching. The implementor is allowed to modify the reference time. + * @return A new Calendar instance (or the same) containing the time for next execution. + */ + Calendar nextExecution(Calendar reference); + + /** + * Calculate the latest cronjob execution time that happens before or exactly at the given refernce time. + * + * @param reference Position in time to start searching. The implementor is allowed to modify the reference time. + * @return A new Calendar instance (or the same) containing the time of the last execution. + */ + Calendar previousExecution(Calendar reference); + + /** + * Execute this cronjob. + * + * @param time The point in time this execution was scheduled. In case of a missed cronjob, the actual time of + * this call might be much later. + * @param controller Back-reference that allows to use repositories. + */ + void executeAt(Calendar time, CronjobController controller); + + /** + * Get a name for this cronjob, that can be presented to the user in the frontend. + * + * @return A german name of this cronjob. + */ + String getDisplayName(); +} \ No newline at end of file diff --git a/prototype/src/main/java/org/hso/ecommerce/controller/cronjob/Reorder.java b/prototype/src/main/java/org/hso/ecommerce/controller/cronjob/Reorder.java new file mode 100644 index 0000000..f0522d1 --- /dev/null +++ b/prototype/src/main/java/org/hso/ecommerce/controller/cronjob/Reorder.java @@ -0,0 +1,164 @@ +package org.hso.ecommerce.controller.cronjob; + +import org.hso.ecommerce.action.booking.CreateBookingAction; +import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction; +import org.hso.ecommerce.action.cronjob.ReorderAction; +import org.hso.ecommerce.action.cronjob.UpdateOffersAction; +import org.hso.ecommerce.entities.booking.Booking; +import org.hso.ecommerce.entities.booking.BookingAccountEntry; +import org.hso.ecommerce.entities.booking.BookingReason; +import org.hso.ecommerce.entities.shop.Article; +import org.hso.ecommerce.entities.supplier.ArticleOffer; +import org.hso.ecommerce.entities.supplier.Supplier; +import org.hso.ecommerce.entities.supplier.SupplierOrder; +import org.springframework.stereotype.Component; + +import java.sql.Timestamp; +import java.util.Calendar; +import java.util.HashMap; +import java.util.List; + +@Component +class Reorder implements ICronjob { + @Override + public String getDisplayName() { + return "Nachbestellung"; + } + + @Override + public Calendar nextExecution(Calendar reference) { + if (reference.get(Calendar.HOUR_OF_DAY) >= 8) { + reference.add(Calendar.DAY_OF_MONTH, 1); + } + reference.set(Calendar.HOUR_OF_DAY, 8); + reference.set(Calendar.MINUTE, 0); + reference.set(Calendar.SECOND, 0); + reference.set(Calendar.MILLISECOND, 0); + return reference; + } + + @Override + public Calendar previousExecution(Calendar reference) { + if (reference.get(Calendar.HOUR_OF_DAY) < 8) { + reference.add(Calendar.DAY_OF_MONTH, -1); + } + reference.set(Calendar.HOUR_OF_DAY, 8); + reference.set(Calendar.MINUTE, 0); + reference.set(Calendar.SECOND, 0); + reference.set(Calendar.MILLISECOND, 0); + return reference; + } + + /** + * Calculates the amount of ordered articles by customers for the given article type in the time between begin and + * end. + * + * @param article The article to search orders for. + * @param begin The start time for the search (included) + * @param end The end time for the search (excluded) + * @return The number of articles that were ordered by customers in the given range. + */ + private Integer getOrderedAmounts(Article article, Calendar begin, Calendar end, CronjobController controller) { + return controller.customerOrderRepository.countOrdersOfArticleInTimespan( + article.id, + new Timestamp(begin.getTimeInMillis()), new Timestamp(end.getTimeInMillis())); + } + + /** + * Calculates the amount of ordered articles by customers for the given article type in the three days before the + * given reference time. The return-array contains 3 fields: Index 0: Orders 72 to 48 hours ago; Index 1: Orders 48 + * to 24 hours ago; Index 2: Orders 24 to 0 hours ago. + * + * @param article The article for which the customer orders are checked. + * @param time The reference time to use for calculation of the last orders. + * @return A 3-element array containing the orders of the last three days. + */ + private Integer[] getOrderedAmounts(Article article, Calendar time, CronjobController controller) { + Calendar oneDayBefore = (Calendar) time.clone(); + oneDayBefore.add(Calendar.DAY_OF_MONTH, -1); + Calendar twoDaysBefore = (Calendar) time.clone(); + twoDaysBefore.add(Calendar.DAY_OF_MONTH, -2); + Calendar threeDaysBefore = (Calendar) time.clone(); + threeDaysBefore.add(Calendar.DAY_OF_MONTH, -3); + + return new Integer[]{ // + getOrderedAmounts(article, threeDaysBefore, twoDaysBefore, controller), // + getOrderedAmounts(article, twoDaysBefore, oneDayBefore, controller), // + getOrderedAmounts(article, oneDayBefore, time, controller), // + }; + } + + private HashMap mapArticleOffers(List articleOffers) { + HashMap map = new HashMap<>(); + for (ArticleOffer articleOffer : articleOffers) { + ReadSupplierDataAction.ArticleIdentifier identifier = new ReadSupplierDataAction.ArticleIdentifier(articleOffer.manufacturer, articleOffer.articleNumber); + map.put(identifier, articleOffer); + } + return map; + } + + @Override + public void executeAt(Calendar time, CronjobController controller) { + List suppliers = controller.supplierRepository.findAll(); + ReadSupplierDataAction.Result supplierData = new ReadSupplierDataAction(suppliers).finish(); + + // Save the new offers in the database + List allOffers = controller.articleOfferRepository.findAll(); + allOffers = new UpdateOffersAction(allOffers, supplierData.cheapestOffer).finish(); + controller.articleOfferRepository.saveAll(allOffers); + + HashMap mappedOffers = mapArticleOffers(allOffers); + + // Reorder + List
allArticles = controller.articleRepository.findAll(); + for (Article article : allArticles) { + Integer[] orderedAmounts = getOrderedAmounts(article, time, controller); + + Integer undeliveredReorders = controller.supplierOrderRepository + .countUndeliveredReorders(article.related.articleNumber); + + int amountInStock = controller.warehouseBookingPositionSlotEntryRepository + .getByArticle(article.id) + .stream() + .mapToInt(e -> e.newSumSlot) + .sum(); + + ReorderAction action = new ReorderAction(article, orderedAmounts, + undeliveredReorders, + amountInStock, + supplierData.cheapestOffer, mappedOffers); + SupplierOrder order = action.finish(); + if (order != null) { + controller.supplierOrderRepository.save(order); + + // Create bookings for this order + int netPrice = order.totalPriceNet; + int vatPercent = order.ordered.vatPercent; + int vatAmount = netPrice * vatPercent / 100; + int grossPrice = netPrice + vatAmount; + + // Obligation towards the supplier + BookingAccountEntry mainAccount = controller.bookingAccountEntryRepository.getByMain() + .orElseGet(BookingAccountEntry::newMain); + BookingAccountEntry supplierAccount = controller.bookingAccountEntryRepository + .getBySupplier(order.supplier.id) + .orElseGet(() -> BookingAccountEntry.newSupplier(order.supplier)); + BookingReason obligationReason = new BookingReason(order); + Booking obligationBooking = new CreateBookingAction(mainAccount, + supplierAccount, + obligationReason, + grossPrice).finish(); + controller.bookingRepository.save(obligationBooking); + + // Input Tax + BookingAccountEntry vatAccount = controller.bookingAccountEntryRepository.getByVat() + .orElseGet(BookingAccountEntry::newVat); + mainAccount = controller.bookingAccountEntryRepository.getByMain().get(); + BookingReason inputTaxReason = new BookingReason(order); + Booking inputTaxBooking = new CreateBookingAction(vatAccount, mainAccount, inputTaxReason, vatAmount) + .finish(); + controller.bookingRepository.save(inputTaxBooking); + } + } + } +} diff --git a/prototype/src/main/java/org/hso/ecommerce/controller/cronjob/ScheduledCronjob.java b/prototype/src/main/java/org/hso/ecommerce/controller/cronjob/ScheduledCronjob.java new file mode 100644 index 0000000..dc04eb4 --- /dev/null +++ b/prototype/src/main/java/org/hso/ecommerce/controller/cronjob/ScheduledCronjob.java @@ -0,0 +1,17 @@ +package org.hso.ecommerce.controller.cronjob; + +import org.hso.ecommerce.entities.cron.BackgroundJob; + +import java.util.Calendar; + +class ScheduledCronjob { + public final Calendar executionTime; + public final ICronjob cronjob; + public final BackgroundJob model; + + public ScheduledCronjob(Calendar executionTime, ICronjob cronjob, BackgroundJob model) { + this.executionTime = executionTime; + this.cronjob = cronjob; + this.model = model; + } +} \ No newline at end of file