| Line 40... |
Line 40... |
| 40 |
private static float[] stateWidths = new float[]{.6f, 2.1f, 0.7f, .3f, 0.6f, .7f, .5f, .6f, .5f, .6f, .8f};
|
40 |
private static float[] stateWidths = new float[]{.6f, 2.1f, 0.7f, .3f, 0.6f, .7f, .5f, .6f, .5f, .6f, .8f};
|
| 41 |
|
41 |
|
| 42 |
private static float[] igstWidthsCrNote = new float[]{2.6f, 0.7f, .4f, 0.7f, .7f, .6f, 0.6f, 0.9f};
|
42 |
private static float[] igstWidthsCrNote = new float[]{2.6f, 0.7f, .4f, 0.7f, .7f, .6f, 0.6f, 0.9f};
|
| 43 |
private static float[] stateWidthsCrNote = new float[]{2.1f, 0.7f, .3f, 0.6f, .7f, .5f, .6f, .5f, .6f, .8f};
|
43 |
private static float[] stateWidthsCrNote = new float[]{2.1f, 0.7f, .3f, 0.6f, .7f, .5f, .6f, .5f, .6f, .8f};
|
| 44 |
|
44 |
|
| 45 |
private static final Locale indianLocale = Locale.getDefault();
|
45 |
private static final Locale indianLocale = new Locale("en", "IN");
|
| - |
|
46 |
private static final java.text.NumberFormat indianCurrencyFormat = java.text.NumberFormat.getCurrencyInstance(new Locale("en", "IN"));
|
| 46 |
|
47 |
|
| 47 |
private static final Logger LOGGER = LogManager.getLogger(PdfUtils.class);
|
48 |
private static final Logger LOGGER = LogManager.getLogger(PdfUtils.class);
|
| 48 |
|
49 |
|
| 49 |
private static final URL iconUrl = PdfUtils.class.getClassLoader().getResource("sdlogo.png");
|
50 |
private static final URL iconUrl = PdfUtils.class.getClassLoader().getResource("sdlogo.png");
|
| 50 |
private static Image iconImg = null;
|
51 |
private static Image iconImg = null;
|
| Line 724... |
Line 725... |
| 724 |
msAddDataCell(itemTable, String.valueOf(orderItem.getQuantity()), Element.ALIGN_CENTER, false, false);
|
725 |
msAddDataCell(itemTable, String.valueOf(orderItem.getQuantity()), Element.ALIGN_CENTER, false, false);
|
| 725 |
|
726 |
|
| 726 |
if (isMargin) {
|
727 |
if (isMargin) {
|
| 727 |
float grossSaleTotal = orderItem.getNetAmount() - taxAmount;
|
728 |
float grossSaleTotal = orderItem.getNetAmount() - taxAmount;
|
| 728 |
float grossSalePerUnit = grossSaleTotal / orderItem.getQuantity();
|
729 |
float grossSalePerUnit = grossSaleTotal / orderItem.getQuantity();
|
| 729 |
msAddDataCell(itemTable, String.format("%.2f", grossSalePerUnit), Element.ALIGN_RIGHT, false, false);
|
730 |
msAddDataCell(itemTable, formatIndianCurrency(grossSalePerUnit), Element.ALIGN_RIGHT, false, false);
|
| 730 |
totalGrossSale += grossSaleTotal;
|
731 |
totalGrossSale += grossSaleTotal;
|
| 731 |
} else {
|
732 |
} else {
|
| 732 |
msAddDataCell(itemTable, String.format("%.2f", orderItem.getRate()), Element.ALIGN_RIGHT, false, false);
|
733 |
msAddDataCell(itemTable, formatIndianCurrency(orderItem.getRate()), Element.ALIGN_RIGHT, false, false);
|
| 733 |
}
|
734 |
}
|
| 734 |
totalNetAmount += orderItem.getNetAmount();
|
735 |
totalNetAmount += orderItem.getNetAmount();
|
| 735 |
msAddDataCell(itemTable, String.format("%.2f", orderItem.getAmount()), Element.ALIGN_RIGHT, false, false);
|
736 |
msAddDataCell(itemTable, formatIndianCurrency(orderItem.getAmount()), Element.ALIGN_RIGHT, false, false);
|
| 736 |
String rateText;
|
737 |
String rateText;
|
| 737 |
if (stateGst) {
|
738 |
if (stateGst) {
|
| 738 |
rateText = String.format("CGST %.1f%%\n+ SGST %.1f%%", orderItem.getCgstRate(), orderItem.getSgstRate());
|
739 |
rateText = String.format("CGST %.1f%%\n+ SGST %.1f%%", orderItem.getCgstRate(), orderItem.getSgstRate());
|
| 739 |
} else {
|
740 |
} else {
|
| 740 |
rateText = String.format("IGST %.1f%%", orderItem.getIgstRate());
|
741 |
rateText = String.format("IGST %.1f%%", orderItem.getIgstRate());
|
| 741 |
}
|
742 |
}
|
| 742 |
msAddDataCell(itemTable, rateText, Element.ALIGN_CENTER, false, false);
|
743 |
msAddDataCell(itemTable, rateText, Element.ALIGN_CENTER, false, false);
|
| 743 |
msAddDataCell(itemTable, String.format("%.2f", taxAmount), Element.ALIGN_RIGHT, false, false);
|
744 |
msAddDataCell(itemTable, formatIndianCurrency(taxAmount), Element.ALIGN_RIGHT, false, false);
|
| 744 |
msAddDataCell(itemTable, String.format("%.0f", orderItem.getNetAmount()), Element.ALIGN_RIGHT, false, false);
|
745 |
msAddDataCell(itemTable, formatIndianCurrency(orderItem.getNetAmount()), Element.ALIGN_RIGHT, false, false);
|
| 745 |
|
746 |
|
| 746 |
totalTaxable += orderItem.getAmount();
|
747 |
totalTaxable += orderItem.getAmount();
|
| 747 |
totalTaxAmount += taxAmount;
|
748 |
totalTaxAmount += taxAmount;
|
| 748 |
totalCgst += orderItem.getCgstAmount();
|
749 |
totalCgst += orderItem.getCgstAmount();
|
| 749 |
totalSgst += orderItem.getSgstAmount();
|
750 |
totalSgst += orderItem.getSgstAmount();
|
| Line 760... |
Line 761... |
| 760 |
totalSpan.setBorderColor(MS_BORDER);
|
761 |
totalSpan.setBorderColor(MS_BORDER);
|
| 761 |
totalSpan.setBackgroundColor(MS_TOTAL_BG);
|
762 |
totalSpan.setBackgroundColor(MS_TOTAL_BG);
|
| 762 |
totalSpan.setPadding(4f);
|
763 |
totalSpan.setPadding(4f);
|
| 763 |
itemTable.addCell(totalSpan);
|
764 |
itemTable.addCell(totalSpan);
|
| 764 |
|
765 |
|
| 765 |
msAddDataCell(itemTable, isMargin ? String.format("%.2f", totalGrossSale) : "", Element.ALIGN_RIGHT, true, true);
|
766 |
msAddDataCell(itemTable, isMargin ? formatIndianCurrency(totalGrossSale) : "", Element.ALIGN_RIGHT, true, true);
|
| 766 |
msAddDataCell(itemTable, String.format("%.2f", totalTaxable), Element.ALIGN_RIGHT, true, true);
|
767 |
msAddDataCell(itemTable, formatIndianCurrency(totalTaxable), Element.ALIGN_RIGHT, true, true);
|
| 767 |
msAddDataCell(itemTable, "\u2014", Element.ALIGN_CENTER, false, true);
|
768 |
msAddDataCell(itemTable, "\u2014", Element.ALIGN_CENTER, false, true);
|
| 768 |
msAddDataCell(itemTable, String.format("%.2f", totalTaxAmount), Element.ALIGN_RIGHT, true, true);
|
769 |
msAddDataCell(itemTable, formatIndianCurrency(totalTaxAmount), Element.ALIGN_RIGHT, true, true);
|
| 769 |
msAddDataCell(itemTable, String.format("%.0f", totalNetAmount), Element.ALIGN_RIGHT, true, true);
|
770 |
msAddDataCell(itemTable, formatIndianCurrency(totalNetAmount), Element.ALIGN_RIGHT, true, true);
|
| 770 |
|
771 |
|
| 771 |
document.add(itemTable);
|
772 |
document.add(itemTable);
|
| 772 |
|
773 |
|
| 773 |
// ── Bottom: Info (left) + Summary (right) + Amount in words ──
|
774 |
// ── Bottom: Info (left) + Summary (right) + Amount in words ──
|
| 774 |
float totalInvoiceValue = isMargin ? (totalGrossSale + totalTaxAmount) : totalNetAmount;
|
775 |
float totalInvoiceValue = isMargin ? (totalGrossSale + totalTaxAmount) : totalNetAmount;
|
| Line 806... |
Line 807... |
| 806 |
PdfPTable sumTable = new PdfPTable(2);
|
807 |
PdfPTable sumTable = new PdfPTable(2);
|
| 807 |
sumTable.setWidthPercentage(100);
|
808 |
sumTable.setWidthPercentage(100);
|
| 808 |
sumTable.setWidths(new float[]{1.4f, 1f});
|
809 |
sumTable.setWidths(new float[]{1.4f, 1f});
|
| 809 |
|
810 |
|
| 810 |
if (isMargin) {
|
811 |
if (isMargin) {
|
| 811 |
msAddSummaryRow(sumTable, "Total Selling Price", String.format("Rs. %.2f", totalGrossSale), false);
|
812 |
msAddSummaryRow(sumTable, "Total Selling Price", "Rs. " + formatIndianCurrency(totalGrossSale), false);
|
| 812 |
msAddSummaryRow(sumTable, "GST on Margin", String.format("Rs. %.2f", totalTaxAmount), false);
|
813 |
msAddSummaryRow(sumTable, "GST on Margin", "Rs. " + formatIndianCurrency(totalTaxAmount), false);
|
| 813 |
} else {
|
814 |
} else {
|
| 814 |
msAddSummaryRow(sumTable, "Total Taxable Value", String.format("Rs. %.2f", totalTaxable), false);
|
815 |
msAddSummaryRow(sumTable, "Total Taxable Value", "Rs. " + formatIndianCurrency(totalTaxable), false);
|
| 815 |
msAddSummaryRow(sumTable, "Total GST", String.format("Rs. %.2f", totalTaxAmount), false);
|
816 |
msAddSummaryRow(sumTable, "Total GST", "Rs. " + formatIndianCurrency(totalTaxAmount), false);
|
| 816 |
}
|
817 |
}
|
| 817 |
msAddSummaryRow(sumTable, "Total Invoice Value", String.format("Rs. %.2f", totalInvoiceValue), true);
|
818 |
msAddSummaryRow(sumTable, "Total Invoice Value", "Rs. " + formatIndianCurrency(totalInvoiceValue), true);
|
| 818 |
summaryCell.addElement(sumTable);
|
819 |
summaryCell.addElement(sumTable);
|
| 819 |
bottomTable.addCell(summaryCell);
|
820 |
bottomTable.addCell(summaryCell);
|
| 820 |
|
821 |
|
| 821 |
// Row 2: empty (left) + Amount in words (right) — no gap
|
822 |
// Row 2: empty (left) + Amount in words (right) — no gap
|
| 822 |
PdfPCell emptyLeft = new PdfPCell(new Phrase("", MS_NORMAL));
|
823 |
PdfPCell emptyLeft = new PdfPCell(new Phrase("", MS_NORMAL));
|
| Line 1176... |
Line 1177... |
| 1176 |
e.printStackTrace();
|
1177 |
e.printStackTrace();
|
| 1177 |
}
|
1178 |
}
|
| 1178 |
}
|
1179 |
}
|
| 1179 |
|
1180 |
|
| 1180 |
private static String toAmountInWords(float amount) {
|
1181 |
private static String toAmountInWords(float amount) {
|
| - |
|
1182 |
int rupees = (int) amount;
|
| - |
|
1183 |
int paise = Math.round((amount - rupees) * 100);
|
| - |
|
1184 |
StringBuilder sb = new StringBuilder("Rs. ");
|
| - |
|
1185 |
sb.append(StringUtils.capitalize(indianNumberToWords(rupees)));
|
| - |
|
1186 |
if (paise > 0) {
|
| - |
|
1187 |
sb.append(" and ");
|
| 1181 |
RuleBasedNumberFormat amountInWordsFormat = new RuleBasedNumberFormat(indianLocale, RuleBasedNumberFormat.SPELLOUT);
|
1188 |
RuleBasedNumberFormat fmt = new RuleBasedNumberFormat(indianLocale, RuleBasedNumberFormat.SPELLOUT);
|
| - |
|
1189 |
sb.append(StringUtils.capitalize(fmt.format(paise)));
|
| - |
|
1190 |
sb.append(" Paise");
|
| - |
|
1191 |
} else {
|
| - |
|
1192 |
sb.append(" Only");
|
| - |
|
1193 |
}
|
| - |
|
1194 |
return sb.toString();
|
| - |
|
1195 |
}
|
| - |
|
1196 |
|
| - |
|
1197 |
/**
|
| - |
|
1198 |
* Convert number to Indian English words (lakh, crore system).
|
| - |
|
1199 |
*/
|
| - |
|
1200 |
private static String indianNumberToWords(int number) {
|
| - |
|
1201 |
if (number == 0) return "zero";
|
| - |
|
1202 |
String[] ones = {"", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
|
| - |
|
1203 |
"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen",
|
| - |
|
1204 |
"eighteen", "nineteen"};
|
| - |
|
1205 |
String[] tens = {"", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};
|
| - |
|
1206 |
|
| - |
|
1207 |
if (number < 0) return "minus " + indianNumberToWords(-number);
|
| - |
|
1208 |
|
| 1182 |
StringBuilder amountInWords = new StringBuilder("Rs. ");
|
1209 |
StringBuilder words = new StringBuilder();
|
| - |
|
1210 |
if (number / 10000000 > 0) {
|
| 1183 |
amountInWords.append(StringUtils.capitalize(amountInWordsFormat.format((int) amount)));
|
1211 |
words.append(indianNumberToWords(number / 10000000)).append(" crore ");
|
| - |
|
1212 |
number %= 10000000;
|
| - |
|
1213 |
}
|
| 1184 |
amountInWords.append(" and ");
|
1214 |
if (number / 100000 > 0) {
|
| - |
|
1215 |
words.append(indianNumberToWords(number / 100000)).append(" lakh ");
|
| - |
|
1216 |
number %= 100000;
|
| - |
|
1217 |
}
|
| - |
|
1218 |
if (number / 1000 > 0) {
|
| 1185 |
amountInWords.append(StringUtils.capitalize(amountInWordsFormat.format((int) (amount * 100) % 100)));
|
1219 |
words.append(indianNumberToWords(number / 1000)).append(" thousand ");
|
| - |
|
1220 |
number %= 1000;
|
| - |
|
1221 |
}
|
| - |
|
1222 |
if (number / 100 > 0) {
|
| - |
|
1223 |
words.append(ones[number / 100]).append(" hundred ");
|
| - |
|
1224 |
number %= 100;
|
| - |
|
1225 |
}
|
| - |
|
1226 |
if (number > 0) {
|
| - |
|
1227 |
if (words.length() > 0) words.append("and ");
|
| - |
|
1228 |
if (number < 20) {
|
| 1186 |
amountInWords.append(" paise");
|
1229 |
words.append(ones[number]);
|
| - |
|
1230 |
} else {
|
| - |
|
1231 |
words.append(tens[number / 10]);
|
| - |
|
1232 |
if (number % 10 > 0) words.append("-").append(ones[number % 10]);
|
| - |
|
1233 |
}
|
| - |
|
1234 |
}
|
| 1187 |
return amountInWords.toString();
|
1235 |
return words.toString().trim();
|
| - |
|
1236 |
}
|
| - |
|
1237 |
|
| - |
|
1238 |
/**
|
| - |
|
1239 |
* Format amount in Indian comma style: 1,25,129.00
|
| - |
|
1240 |
*/
|
| - |
|
1241 |
static String formatIndianCurrency(double amount) {
|
| - |
|
1242 |
String formatted = indianCurrencyFormat.format(amount);
|
| - |
|
1243 |
// Remove currency symbol, keep just the number with commas
|
| - |
|
1244 |
return formatted.replaceAll("[^0-9,.]", "").trim();
|
| 1188 |
}
|
1245 |
}
|
| 1189 |
|
1246 |
|
| 1190 |
public static void generateAndWriteCustomerCreditNotes(List<CreditNotePdfModel> creditNotes, OutputStream outputStream) {
|
1247 |
public static void generateAndWriteCustomerCreditNotes(List<CreditNotePdfModel> creditNotes, OutputStream outputStream) {
|
| 1191 |
Document document = new Document();
|
1248 |
Document document = new Document();
|
| 1192 |
document.setMargins(0, 0, 25, 0);
|
1249 |
document.setMargins(0, 0, 25, 0);
|