Blame | Last modification | View Log | RSS feed
package com.spice.profitmandi.service.inventory;import com.spice.profitmandi.common.util.FormattingUtils;import java.math.BigDecimal;import java.math.RoundingMode;import java.time.LocalDate;import java.time.LocalDateTime;import java.time.LocalTime;import java.util.ArrayList;import java.util.List;/*** What a return is worth when Finance settles it as B2C after NIC refused it for a cancelled or* invalid buyer GSTIN: every returned line at its value net of GST, in whole rupees.* <p>* Standard accounting rounding - each line's net value is rounded HALF_UP to the rupee, and the* refund is the sum of those lines, so the line table and the total always agree. The gross is* rounded the same way, and the GST retained is simply gross minus refund. The same object feeds* the Finance popup, both notification mails and the server-side check of the amount Finance types* in, so the three can never disagree.*/public class B2cRefundQuote {public static class Line {private final int refId;private final String description;private final long quantity;private final BigDecimal grossAmount;private final BigDecimal gstRate;private final long netAmount;Line(int refId, String description, long quantity, BigDecimal grossAmount, BigDecimal gstRate) {this.refId = refId;this.description = description;this.quantity = quantity;this.grossAmount = grossAmount.setScale(0, RoundingMode.HALF_UP);this.gstRate = gstRate;BigDecimal divisor = BigDecimal.ONE.add(gstRate.movePointLeft(2));// One rounding step, straight to the rupee - rounding to paisa first would double-round.this.netAmount = grossAmount.divide(divisor, 0, RoundingMode.HALF_UP).longValueExact();}/** Order id in the invoice-return flow, inventory item id in the debit-note flow. */public int getRefId() {return refId;}public String getDescription() {return description;}public long getQuantity() {return quantity;}public long getGrossAmount() {return grossAmount.longValueExact();}public BigDecimal getGstRate() {return gstRate;}public long getNetAmount() {return netAmount;}public String getFormattedGross() {return FormattingUtils.formatDigit(getGrossAmount());}public String getFormattedNet() {return FormattingUtils.formatDigit(netAmount);}public String getFormattedGstRate() {return gstRate.stripTrailingZeros().toPlainString();}}private int purchaseReturnOrderId;private String flow;private String invoiceNumber;private int fofoId;private String partnerName;private String partnerCode;private String buyerGstin;private String reason;private String stage;private int attempts;private LocalDateTime lastAttemptAt;private String lastAttemptBy;private final List<Line> lines = new ArrayList<>();void addLine(int refId, String description, long quantity, BigDecimal grossAmount, BigDecimal gstRate) {lines.add(new Line(refId, description, quantity, grossAmount, gstRate));}public List<Line> getLines() {return lines;}public long getGrossTotal() {return lines.stream().mapToLong(Line::getGrossAmount).sum();}public long getRefundAmount() {return lines.stream().mapToLong(Line::getNetAmount).sum();}public long getGstRetained() {return getGrossTotal() - getRefundAmount();}public long getTotalQuantity() {return lines.stream().mapToLong(Line::getQuantity).sum();}public String getFormattedGrossTotal() {return FormattingUtils.formatDigit(getGrossTotal());}public String getFormattedRefundAmount() {return FormattingUtils.formatDigit(getRefundAmount());}public String getFormattedGstRetained() {return FormattingUtils.formatDigit(getGstRetained());}/** The B2C option stays open until the end of the calendar day of the latest refusal. */public LocalDateTime getAvailableUntil() {return lastAttemptAt == null ? null : lastAttemptAt.toLocalDate().atTime(LocalTime.of(23, 59, 59));}public boolean isAvailable() {return lastAttemptAt != null && lastAttemptAt.toLocalDate().equals(LocalDate.now());}public String getFormattedAvailableUntil() {return getAvailableUntil() == null ? "" : FormattingUtils.format(getAvailableUntil());}public String getFormattedLastAttemptAt() {return lastAttemptAt == null ? "" : FormattingUtils.format(lastAttemptAt);}public int getPurchaseReturnOrderId() {return purchaseReturnOrderId;}public void setPurchaseReturnOrderId(int purchaseReturnOrderId) {this.purchaseReturnOrderId = purchaseReturnOrderId;}public String getFlow() {return flow;}public void setFlow(String flow) {this.flow = flow;}public String getInvoiceNumber() {return invoiceNumber;}public void setInvoiceNumber(String invoiceNumber) {this.invoiceNumber = invoiceNumber;}public int getFofoId() {return fofoId;}public void setFofoId(int fofoId) {this.fofoId = fofoId;}public String getPartnerName() {return partnerName;}public void setPartnerName(String partnerName) {this.partnerName = partnerName;}public String getPartnerCode() {return partnerCode;}public void setPartnerCode(String partnerCode) {this.partnerCode = partnerCode;}public String getBuyerGstin() {return buyerGstin;}public void setBuyerGstin(String buyerGstin) {this.buyerGstin = buyerGstin;}public String getReason() {return reason;}public void setReason(String reason) {this.reason = reason;}public String getStage() {return stage;}public void setStage(String stage) {this.stage = stage;}public int getAttempts() {return attempts;}public void setAttempts(int attempts) {this.attempts = attempts;}public LocalDateTime getLastAttemptAt() {return lastAttemptAt;}public void setLastAttemptAt(LocalDateTime lastAttemptAt) {this.lastAttemptAt = lastAttemptAt;}public String getLastAttemptBy() {return lastAttemptBy;}public void setLastAttemptBy(String lastAttemptBy) {this.lastAttemptBy = lastAttemptBy;}}