package eu.ggnet.dwoss.redtape.reporting; import eu.ggnet.dwoss.rules.DocumentType; import eu.ggnet.dwoss.rules.PositionType; import eu.ggnet.dwoss.rules.TradeName; import eu.ggnet.dwoss.util.MathUtil; import eu.ggnet.dwoss.util.UserInfoException; import eu.ggnet.dwoss.redtape.entity.PositionBuilder; import eu.ggnet.dwoss.redtape.entity.Position; import eu.ggnet.dwoss.redtape.entity.Document; import eu.ggnet.dwoss.redtape.entity.Dossier; import eu.ggnet.dwoss.stock.entity.LogicTransaction; import eu.ggnet.dwoss.stock.entity.StockTransaction; import eu.ggnet.dwoss.stock.entity.StockUnit; import eu.ggnet.dwoss.uniqueunit.entity.UniqueUnit; import eu.ggnet.dwoss.uniqueunit.entity.PriceType; import eu.ggnet.dwoss.uniqueunit.entity.Product; import java.util.*; import java.util.stream.Collectors; import javax.ejb.*; import javax.ejb.embeddable.EJBContainer; import javax.inject.Inject; import javax.naming.NamingException; import javax.persistence.EntityManager; import org.junit.*; import eu.ggnet.dwoss.configuration.GlobalConfig; import eu.ggnet.dwoss.configuration.SystemConfig; import eu.ggnet.dwoss.customer.api.CustomerMetaData; import eu.ggnet.dwoss.customer.api.CustomerService; import eu.ggnet.dwoss.customer.assist.CustomerPu; import eu.ggnet.dwoss.customer.assist.gen.CustomerGeneratorOperation; import eu.ggnet.dwoss.mandator.api.service.WarrantyService; import eu.ggnet.dwoss.mandator.api.value.*; import eu.ggnet.dwoss.receipt.gen.ReceiptGeneratorOperation; import eu.ggnet.dwoss.redtape.RedTapeAgent; import eu.ggnet.dwoss.redtape.api.RedTapeHookService; import eu.ggnet.dwoss.redtape.assist.RedTapePu; import eu.ggnet.dwoss.redtape.RedTapeWorker; import eu.ggnet.dwoss.redtape.gen.RedTapeGeneratorOperation; import eu.ggnet.dwoss.report.ReportAgent; import eu.ggnet.dwoss.report.assist.ReportPu; import eu.ggnet.dwoss.report.eao.ReportLineEao; import eu.ggnet.dwoss.report.entity.ReportLine; import static eu.ggnet.dwoss.rules.TradeName.*; import eu.ggnet.dwoss.spec.assist.SpecPu; import eu.ggnet.dwoss.stock.StockAgent; import eu.ggnet.dwoss.stock.assist.StockPu; import eu.ggnet.dwoss.stock.assist.Stocks; import eu.ggnet.dwoss.uniqueunit.assist.UniqueUnitPu; import eu.ggnet.dwoss.uniqueunit.assist.UniqueUnits; import eu.ggnet.dwoss.uniqueunit.eao.ProductEao; import eu.ggnet.dwoss.uniqueunit.format.UniqueUnitFormater; import eu.ggnet.dwoss.util.interactiveresult.Result; import static eu.ggnet.dwoss.redtape.entity.Document.Condition.CANCELED; import static eu.ggnet.dwoss.report.entity.ReportLine.SingleReferenceType.WARRANTY; import static eu.ggnet.dwoss.rules.DocumentType.BLOCK; import static eu.ggnet.dwoss.rules.PositionType.*; import static eu.ggnet.dwoss.rules.ProductGroup.COMMENTARY; import static eu.ggnet.dwoss.uniqueunit.entity.UniqueUnit.Identifier.REFURBISHED_ID; import static org.fest.assertions.api.Assertions.*; import static org.junit.Assert.*; /** * * @author oliver.guenther */ public class RedTapeCloserOperationIT { class RedTapeHookStup implements RedTapeHookService { @Override public Result<List<Position>> elaborateUnitPosition(Position p, long documentId) throws UserInfoException { return new Result<>(Arrays.asList(p, Position.builder() .amount(p.getAmount()) .price(10.) .tax(p.getTax()) .afterTaxPrice(MathUtil.roundedApply(10, GlobalConfig.TAX, 0.)) .serialNumber(p.getSerial()) .refurbishedId(p.getRefurbishedId()) .bookingAccount(1000) .type(PRODUCT_BATCH) .tax(GlobalConfig.TAX) .uniqueUnitId(p.getUniqueUnitId()) .uniqueUnitProductId(eao.findByPartNo(WARRANTY_PART_NO).getId()) .name("Warranty Position") .description("Warranty Position") .build() )); } @Override public Result<List<Position>> addWarrantyForUnitPosition(Position p, long documentId) throws UserInfoException { return null; } } static class WarrantyServiceStup implements WarrantyService { @Override public boolean isWarranty(String partNo) { return WARRANTY_PART_NO.equals(partNo); } @Override public TradeName warrantyContractor(String partNo) { return ONESELF; } }; static final String WARRANTY_PART_NO = "DEH2381234"; private final static Random R = new Random(); private EJBContainer container; @Inject private CustomerGeneratorOperation customerGenerator; @Inject private ReceiptGeneratorOperation receiptGenerator; @Inject private RedTapeGeneratorOperation redTapeGenerator; @EJB private RedTapeCloser redTapeCloser; @EJB private ReportAgent reportAgent; @EJB private RedTapeWorker redTapeWorker; @EJB private RedTapeAgent redTapeAgent; @Inject private CustomerService customerService; @Inject private ProductEao eao; @Inject private StockAgent stockAgent; @Inject private RedTapeCloserOpertaionItBean redTapeCloserOpertaionItBean; @Inject private PostLedger postLedger; private SpecialSystemCustomers systemCustomers; private ReceiptCustomers receiptCustomers; @Before public void setUp() throws NamingException { Map<String, Object> c = new HashMap<>(); c.putAll(CustomerPu.CMP_IN_MEMORY); c.putAll(SpecPu.CMP_IN_MEMORY); c.putAll(UniqueUnitPu.CMP_IN_MEMORY); c.putAll(StockPu.CMP_IN_MEMORY); c.putAll(RedTapePu.CMP_IN_MEMORY); c.putAll(ReportPu.CMP_IN_MEMORY); c.putAll(SystemConfig.OPENEJB_EJB_XML_DISCOVER); c.putAll(SystemConfig.OPENEJB_LOG_WARN); container = EJBContainer.createEJBContainer(c); container.getContext().bind("inject", this); } @After public void tearDown() { container.close(); } private void warnIfStockSizeDidNotChange(long stockSize) { if ( stockSize == stockAgent.count(StockUnit.class) ) { System.err.println("Stock size din't change, this is highly unlikely. To solve:\n" + " - Rerun Test multiple times\n" + " - Increase the amount of generator\n" + " - Manipulate Stock before rollout to ensure the right behavior"); } } /** * Tests if something gets closed and if the appropriated stock units are gone. * <p> * @throws UserInfoException */ @Test public void testDayClosing() throws UserInfoException { assertFalse(customerGenerator.makeCustomers(10).isEmpty()); receiptCustomers = customerGenerator.makeReceiptCustomers(ACER); systemCustomers = customerGenerator.makeSpecialCustomers(BLOCK); assertFalse(systemCustomers == null); assertFalse(receiptCustomers == null); assertFalse(receiptGenerator.makeUniqueUnits(200, true, true).isEmpty()); assertFalse(redTapeGenerator.makeSalesDossiers(30).isEmpty()); //dossier ids from created blockers List<Long> blockerIds = buildBlocker().stream().mapToLong(d -> d.getId()).boxed().collect(Collectors.toList()); assertThat( stockAgent.findAllEager(StockTransaction.class) .stream() .map(StockTransaction::getPositions) .flatMap(Collection::stream) .anyMatch(t -> t.getStockUnit() != null) ) .overridingErrorMessage("Their exist a StockTransaction, which is not complete (blocking a stockUnit), impossible!") .isFalse(); long stockUnits = stockAgent.count(StockUnit.class); assertThat(stockUnits).isPositive(); List<LogicTransaction> allLts = stockAgent.findAllEager(LogicTransaction.class); assertThat(allLts.size()) .overridingErrorMessage("No LogicTransactions exist, impossible!") .isPositive(); redTapeCloser.executeManual("Junit"); List<Dossier> blockerDossiers = new ArrayList<>(); for (Long blockerId : blockerIds) { blockerDossiers.add(redTapeAgent.findByIdEager(Dossier.class, blockerId)); } assertEquals("More/Less Blockers than expected passed closing", 3, blockerDossiers.stream().filter(d -> d.isClosed()).collect(Collectors.toList()).size()); warnIfStockSizeDidNotChange(stockUnits); List<Dossier> allDossiers = redTapeAgent.findAllEager(Dossier.class); for (Dossier dos : allDossiers) { if ( dos.isClosed() ) { for (Document doc : dos.getActiveDocuments()) { if ( doc.containsAny(CANCELED) ) continue; // These are just ignored. for (Integer uuId : doc.getPositionsUniqueUnitIds()) { StockUnit su = stockAgent.findStockUnitByUniqueUnitIdEager(uuId); assertNull("There is a StockUnit for a closed Dossier (doc.id= " + doc.getId() + "):\n" + dos.toMultiLine() + "\n\n" + su + "\n\n" + "Original LTS: " + allLts.stream().filter(x -> x.getUnits().contains(su)).findAny().orElse(null), su); } } } else { for (Integer uuId : dos.getRelevantUniqueUnitIds()) { StockUnit su = stockAgent.findStockUnitByUniqueUnitIdEager(uuId); assertNotNull("There is no StockUnit for an open Dossier\n" + dos, su); } } } long reportSize = reportAgent.count(ReportLine.class); assertFalse(reportSize == 0); redTapeCloser.executeManual("Junit"); assertEquals("Second call should not add anything new", reportSize, reportAgent.count(ReportLine.class)); } @Test public void testDayClosingWarrenty() throws UserInfoException { long customerId = customerGenerator.makeCustomer(); UniqueUnit uu = receiptGenerator.makeUniqueUnits(1, true, true).get(0); Product p = redTapeCloserOpertaionItBean.makeWarrantyProduct(); CustomerMetaData metaCustomer = customerService.asCustomerMetaData(customerId); assertFalse("no customer in database", customerId == 0); assertFalse("bo unique unit in database", uu == null); assertFalse("no customer meta data found", metaCustomer == null); assertFalse("no warranty product in database", p == null); // Create a dossier on a random customer. Dossier dos = redTapeWorker.create(customerId, false, "Generated by RedTapeGeneratorOperation.makeSalesDossiers()"); Document doc = dos.getActiveDocuments(DocumentType.ORDER).get(0); double price = uu.getPrice(PriceType.CUSTOMER); if ( price < 0.001 ) price = uu.getPrice(PriceType.RETAILER); if ( price < 0.001 ) price = 1111.11; Position pos = new PositionBuilder() .setType(PositionType.UNIT) .setUniqueUnitId(uu.getId()) .setUniqueUnitProductId(uu.getProduct().getId()) .setPrice(price) .setTax(GlobalConfig.TAX) .setAfterTaxPrice(MathUtil.roundedApply(price, GlobalConfig.TAX, 0.)) .setDescription(UniqueUnitFormater.toDetailedDiscriptionLine(uu)) .setName(UniqueUnitFormater.toPositionName(uu)) .setBookingAccount(-1) .createPosition(); pos.setRefurbishedId(uu.getRefurbishId()); doc.appendAll(new RedTapeHookStup().elaborateUnitPosition(pos, doc.getId()).getPayload()); doc = redTapeWorker.update(doc, null, "JUnit"); doc.add(Document.Condition.PAID); doc.add(Document.Condition.PICKED_UP); doc.setType(DocumentType.INVOICE); doc = redTapeWorker.update(doc, null, "JUnit"); redTapeCloser.executeManual("Junit"); doc = redTapeAgent.findByIdEager(Document.class, doc.getId()); doc.setType(DocumentType.COMPLAINT); doc.setDirective(Document.Directive.WAIT_FOR_COMPLAINT_COMPLETION); doc = redTapeWorker.update(doc, null, "JUnit"); redTapeCloser.executeManual("Junit"); redTapeCloserOpertaionItBean.checkReferences(dos.getId()); } @Stateless public static class RedTapeCloserOpertaionItBean { @Inject private ReportLineEao reportEao; @Inject @UniqueUnits private EntityManager uuEm; @Inject @Stocks private EntityManager stockEm; public void checkReferences(long dossierId) { List<ReportLine> allLines = reportEao.findAll(); List<ReportLine> collect = allLines.stream().filter((line) -> { return line.getPositionType().equals(PositionType.PRODUCT_BATCH) && line.getDossierId() == dossierId; }).collect(Collectors.toList()); assertEquals("Assert ten warranties to be present", 2, collect.size()); for (ReportLine line : collect) { ReportLine reference = line.getReference(WARRANTY); assertFalse("Line has no unit reference " + line, reference == null); assertEquals("Assert equal dossier id in reference", reference.getDossierId(), dossierId); assertFalse("Contractor has not been set", reference.getContractor() == null); } } public Product makeWarrantyProduct() { Product p = new Product(COMMENTARY, HP, WARRANTY_PART_NO, "Warranty Product"); uuEm.persist(p); return p; } //delete Stockunit and logictransaction for specific stockunit public void deleteStockUnit(int stockUnitId) { StockUnit unit = stockEm.find(StockUnit.class, stockUnitId); LogicTransaction transaction = stockEm.find(LogicTransaction.class, unit.getLogicTransaction().getId()); stockEm.remove(unit); stockEm.remove(transaction); } } /** * builds 4 blocker dossiers in the following manner: * - 1 comment only blocker * - 1 comment plus non unit/comment blocker * - 1 unit with stockunit blocker * - 1 unit without stockunit blocker * */ private List<Dossier> buildBlocker() { Long customerId = (Long)systemCustomers.getSpecialCustomers().keySet().toArray()[0]; Long receiptId = (Long)receiptCustomers.getReceiptCustomers().values().toArray()[0]; Dossier d1 = redTapeWorker.create(customerId, R.nextBoolean(), "JUNIT"); d1.getActiveDocuments(BLOCK).get(0).append(Position.builder() .amount(1) .type(PositionType.COMMENT) .name("Comment") .description("Comment") .bookingAccount(postLedger.get(PositionType.COMMENT).orElse(-1)) .build()); Dossier d2 = redTapeWorker.create(customerId, R.nextBoolean(), "JUNIT"); d2.getActiveDocuments(BLOCK).get(0).append(Position.builder() .amount(1) .type(PositionType.COMMENT) .name("Comment") .description("Comment") .bookingAccount(postLedger.get(PositionType.COMMENT).orElse(-1)) .build()); d2.getActiveDocuments(BLOCK).get(0).append(Position.builder() .type(PositionType.SERVICE) .price(100) .tax(GlobalConfig.TAX) .afterTaxPrice(MathUtil.roundedApply(100, GlobalConfig.TAX, 0.)) .name("Service") .description("Service") .amount(1) .bookingAccount(postLedger.get(PositionType.SERVICE).orElse(-1)) .build()); UniqueUnit unit1 = receiptGenerator.makeUniqueUnits(1, true, true).get(0); UniqueUnit unit2 = receiptGenerator.makeUniqueUnits(1, true, true).get(0); Dossier d3 = redTapeWorker.create(customerId, R.nextBoolean(), "JUNIT"); d3.getActiveDocuments(BLOCK).get(0).append(Position.builder() .amount(1) .type(PositionType.UNIT) .uniqueUnitId(unit1.getId()) .uniqueUnitProductId(unit1.getProduct().getId()) .price(unit1.getPrice(PriceType.SALE)) .tax(GlobalConfig.TAX) .afterTaxPrice(MathUtil.roundedApply(unit1.getPrice(PriceType.SALE), GlobalConfig.TAX, 0.)) .description(UniqueUnitFormater.toDetailedDiscriptionLine(unit1)) .name(UniqueUnitFormater.toPositionName(unit1)) .bookingAccount(-1) .refurbishedId(unit1.getIdentifier(REFURBISHED_ID)) .build()); Dossier d4 = redTapeWorker.create(customerId, R.nextBoolean(), "JUNIT"); d4.getActiveDocuments(BLOCK).get(0).append(Position.builder() .amount(1) .type(PositionType.UNIT) .uniqueUnitId(unit2.getId()) .uniqueUnitProductId(unit2.getProduct().getId()) .price(unit2.getPrice(PriceType.SALE)) .tax(GlobalConfig.TAX) .afterTaxPrice(MathUtil.roundedApply(unit2.getPrice(PriceType.SALE), GlobalConfig.TAX, 0.)) .description(UniqueUnitFormater.toDetailedDiscriptionLine(unit2)) .name(UniqueUnitFormater.toPositionName(unit2)) .bookingAccount(-1) .refurbishedId(unit2.getIdentifier(REFURBISHED_ID)) .build()); Dossier d5 = redTapeWorker.create(receiptId, R.nextBoolean(), "JUNIT"); d5.getActiveDocuments(BLOCK).get(0).append(Position.builder() .amount(1) .type(PositionType.COMMENT) .name("Comment") .description("Comment") .bookingAccount(postLedger.get(PositionType.COMMENT).orElse(-1)) .build()); redTapeWorker.update(d1.getActiveDocuments(BLOCK).get(0), null, "JUNIT"); redTapeWorker.update(d2.getActiveDocuments(BLOCK).get(0), null, "JUNIT"); redTapeWorker.update(d3.getActiveDocuments(BLOCK).get(0), null, "JUNIT"); redTapeWorker.update(d4.getActiveDocuments(BLOCK).get(0), null, "JUNIT"); redTapeWorker.update(d5.getActiveDocuments(BLOCK).get(0), null, "JUNIT"); redTapeCloserOpertaionItBean.deleteStockUnit(stockAgent.findStockUnitByRefurbishIdEager(unit2.getIdentifier(REFURBISHED_ID)).getId()); return Arrays.asList(d1, d2, d3, d4, d5); } }