Subversion Repositories SmartDukaan

Rev

Rev 37066 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
37066 amit 1
package com.spice.profitmandi.common.document;
2
 
3
import com.spice.profitmandi.common.model.CustomCustomer;
37379 amit 4
import com.spice.profitmandi.common.model.CustomInsurancePolicy;
37066 amit 5
import com.spice.profitmandi.common.model.CustomOrderItem;
6
import com.spice.profitmandi.common.model.CustomPaymentOption;
7
import com.spice.profitmandi.common.model.CustomRetailer;
8
import com.spice.profitmandi.common.model.EWayBillPdfModel;
9
import com.spice.profitmandi.common.model.InvoicePdfModel;
10
import com.spice.profitmandi.common.model.IrnModel;
11
 
37379 amit 12
import java.util.ArrayList;
37066 amit 13
import java.util.List;
14
 
15
/**
16
 * Normalized view of a printable document, consumed by the rendering {@code Section}s.
17
 *
18
 * <p>All four document types (tax invoice V1/V2, delivery challan, debit note, credit note)
19
 * ultimately carry an {@link InvoicePdfModel}; debit/credit notes simply wrap one and override the
20
 * document number/date. This holder resolves those differences once — document number, date,
21
 * {@link DocumentType} and display title — and delegates everything else to the wrapped model, so
22
 * the sections never branch on which source type produced the document.
23
 */
24
public class DocumentData {
25
 
26
    public enum DocumentType {
27
        TAX_INVOICE("Invoice No:", "INVOICE DETAILS", "Total Invoice Value", "invoice"),
28
        DELIVERY_CHALLAN("Challan No:", "CHALLAN DETAILS", "Total Challan Value", "delivery challan"),
29
        DEBIT_NOTE("DN No:", "DEBIT NOTE DETAILS", "Total Debit Note Value", "debit note"),
30
        CREDIT_NOTE("CN No:", "CREDIT NOTE DETAILS", "Total Credit Note Value", "credit note");
31
 
32
        private final String numberLabel;
33
        private final String sectionLabel;
34
        private final String totalValueLabel;
35
        private final String noun;
36
 
37
        DocumentType(String numberLabel, String sectionLabel, String totalValueLabel, String noun) {
38
            this.numberLabel = numberLabel;
39
            this.sectionLabel = sectionLabel;
40
            this.totalValueLabel = totalValueLabel;
41
            this.noun = noun;
42
        }
43
 
44
        /** Label preceding the document number, e.g. "Invoice No:" / "DN No:". */
45
        public String numberLabel() { return numberLabel; }
46
        /** Right-aligned section heading, e.g. "INVOICE DETAILS". */
47
        public String sectionLabel() { return sectionLabel; }
48
        /** Grand-total row label, e.g. "Total Invoice Value". */
49
        public String totalValueLabel() { return totalValueLabel; }
50
        /** Lower-case noun for prose, e.g. "invoice" in "computer-generated invoice". */
51
        public String noun() { return noun; }
52
    }
53
 
54
    private final InvoicePdfModel model;
55
    private final DocumentType type;
56
    private final String title;
57
    private final String documentNumber;
58
    private final String documentDate;
59
    private final String originalInvoiceNumber;
60
    private final String originalInvoiceDate;
61
 
37379 amit 62
    /** Memoized {@link #items()} result — insurance folding runs once per document. */
63
    private List<CustomOrderItem> items;
64
    private boolean itemsBuilt;
65
 
37066 amit 66
    public DocumentData(InvoicePdfModel model, DocumentType type, String title,
67
                        String documentNumber, String documentDate,
68
                        String originalInvoiceNumber, String originalInvoiceDate) {
69
        this.model = model;
70
        this.type = type;
71
        this.title = title;
72
        this.documentNumber = documentNumber;
73
        this.documentDate = documentDate;
74
        this.originalInvoiceNumber = originalInvoiceNumber;
75
        this.originalInvoiceDate = originalInvoiceDate;
76
    }
77
 
78
    public InvoicePdfModel model() { return model; }
79
    public DocumentType type() { return type; }
80
 
81
    /** Upper-cased display title shown in the header banner (e.g. "TAX INVOICE", "DEBIT NOTE"). */
82
    public String title() { return title; }
83
 
84
    public String documentNumber() { return documentNumber; }
85
    public String documentDate() { return documentDate; }
86
 
87
    /** Original document reference shown on a note (e.g. supplier invoice no for a warehouse debit note); null on invoices. */
88
    public String originalInvoiceNumber() { return originalInvoiceNumber; }
89
    public String originalInvoiceDate() { return originalInvoiceDate; }
90
 
91
    public boolean isNote() {
92
        return type == DocumentType.DEBIT_NOTE || type == DocumentType.CREDIT_NOTE;
93
    }
94
 
95
    public CustomCustomer customer() { return model.getCustomer(); }
96
    public CustomRetailer retailer() { return model.getRetailer(); }
37379 amit 97
    /**
98
     * Printable lines: the order items followed by one line per insurance policy.
99
     *
100
     * <p>An extended-warranty / damage-protection policy is not a catalog item, so it has no
101
     * {@code fofo_order_item} row and arrives on the model as a {@link CustomInsurancePolicy}
102
     * instead. It is still a supply on the invoice and must be printed and taxed like any other
103
     * line, so it is folded in here — at the single accessor every section reads — rather than in
104
     * each section. Insurance sold after the device sale gets its own invoice, whose only line is
105
     * the policy; without this the whole table (and therefore the totals) came out empty.
106
     */
107
    public List<CustomOrderItem> items() {
108
        if (!itemsBuilt) {
109
            items = buildItems();
110
            itemsBuilt = true;
111
        }
112
        return items;
113
    }
114
 
115
    private List<CustomOrderItem> buildItems() {
116
        List<CustomInsurancePolicy> policies = model.getInsurancePolicies();
117
        if (policies == null || policies.isEmpty()) {
118
            // No policies: hand back the model's own list untouched so nothing else can shift.
119
            return model.getOrderItems();
120
        }
121
        List<CustomOrderItem> combined = new ArrayList<>();
122
        if (model.getOrderItems() != null) {
123
            combined.addAll(model.getOrderItems());
124
        }
125
        boolean intraState = intraState();
126
        for (CustomInsurancePolicy policy : policies) {
127
            combined.add(toOrderItem(policy, intraState));
128
        }
129
        return combined;
130
    }
131
 
132
    /**
133
     * Maps a policy onto a printable line, mirroring the columns the pre-refactor renderer emitted:
134
     * quantity 1, no discount, the taxable value repeated in the Rate column, and only the tax side
135
     * that applies to this supply populated — matching how real order items are built, so the
136
     * margin-scheme rate column (which sums all three tax amounts) stays correct.
137
     */
138
    private static CustomOrderItem toOrderItem(CustomInsurancePolicy policy, boolean intraState) {
139
        CustomOrderItem item = new CustomOrderItem();
140
        item.setDescription(policy.getDescription());
141
        item.setHsnCode(policy.getHsnCode());
142
        item.setQuantity(1);
143
        item.setRate(policy.getRate());
144
        item.setDiscount(0f);
145
        item.setAmount(policy.getRate());
146
        item.setNetAmount(policy.getNetAmount());
147
        if (intraState) {
148
            item.setCgstRate(policy.getCgstRate());
149
            item.setCgstAmount(policy.getCgstAmount());
150
            item.setSgstRate(policy.getSgstRate());
151
            item.setSgstAmount(policy.getSgstAmount());
152
        } else {
153
            item.setIgstRate(policy.getIgstRate());
154
            item.setIgstAmount(policy.getIgstAmount());
155
        }
156
        return item;
157
    }
158
 
37066 amit 159
    public List<CustomPaymentOption> paymentOptions() { return model.getPaymentOptions(); }
160
    public List<String> creditTerms() { return model.getCreditTerms(); }
161
    public IrnModel irnModel() { return model.getIrnModel(); }
162
    public String irnErrorMessage() { return model.getIrnErrorMessage(); }
163
    public EWayBillPdfModel eWayBill() { return model.geteWayBillPdfModel(); }
164
    public boolean isCancelled() { return model.isCancelled(); }
165
    public boolean isMargin() { return model.isHasMarginSchemeItems(); }
166
    public String customerAddressStateCode() { return model.getCustomerAddressStateCode(); }
167
    public String partnerAddressStateCode() { return model.getPartnerAddressStateCode(); }
168
 
169
    /** Mapped purchase-order number (transaction.order only); null when unmapped — then not printed. */
170
    public String poNumber() { return model.getPoNumber(); }
171
 
172
    /** Order placed date; printed whenever present. */
173
    public String orderDate() { return model.getOrderDate(); }
174
 
175
    /** Intra-state supply iff buyer and supplier are in the same state. Mirrors the legacy rule. */
176
    public boolean intraState() {
177
        return customer().getAddress().getState().equals(retailer().getAddress().getState());
178
    }
179
 
180
    /** State code printed in the supplier block — buyer's for intra-state, partner's for inter-state. */
181
    public String stateCode() {
182
        return intraState() ? customerAddressStateCode() : partnerAddressStateCode();
183
    }
184
 
185
    /** True when any line carries an order id, which adds the "Order Id" column. */
186
    public boolean showOrderId() {
187
        if (items() == null) return false;
188
        for (CustomOrderItem item : items()) {
189
            if (item.getOrderId() != 0) return true;
190
        }
191
        return false;
192
    }
193
}