All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pe.puyu.jticketdesing.core.SweetTicketDesign Maven / Gradle / Ivy

The newest version!
package pe.puyu.jticketdesing.core;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Map;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import com.github.anastaciocintra.escpos.EscPos;
import com.github.anastaciocintra.escpos.EscPos.PinConnector;
import com.github.anastaciocintra.escpos.Style.FontSize;
import com.github.anastaciocintra.escpos.image.BitonalOrderedDither;
import com.github.anastaciocintra.escpos.image.BitonalThreshold;

import pe.puyu.jticketdesing.metadata.TicketPropertiesReader;
import pe.puyu.jticketdesing.util.ImageUtil;
import pe.puyu.jticketdesing.util.QRCodeGenerator;
import pe.puyu.jticketdesing.util.StringUtils;
import pe.puyu.jticketdesing.util.escpos.*;

class Default {
	public final static int QUANTITY_COLUMN_WIDTH = 4;
	public final static int TOTAL_COLUMN_WIDTH = 7;
	public final static int UNIT_PRICE_WIDTH = 7;
}

public class SweetTicketDesign {

	private final JsonObject data;
	private EscPos escpos;
	private final DesignerHelper helper;

	public SweetTicketDesign(JsonObject ticket) {
		this.data = ticket.getAsJsonObject("data");
		this.helper = new DesignerHelper<>(new TicketPropertiesReader(ticket));
	}

	public SweetTicketDesign(String jsonString) {
		this(JsonParser.parseString(jsonString).getAsJsonObject());
	}

	private void initEscPos(ByteArrayOutputStream buffer) throws Exception {
		this.escpos = new EscPos(buffer);
		this.escpos.setCharacterCodeTable(helper.properties().charCodeTable());
	}

	public byte[] getBytes() throws Exception {
		try {
			ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
			initEscPos(byteArrayOutputStream);
			for (int i = 0; i < helper.properties().times(); ++i) {
				designLayout();
			}
			return byteArrayOutputStream.toByteArray();
		} catch (Exception e) {
			throw new Exception(String.format("JTicketDesign Exception: %s", e.getMessage()));
		} finally {
			this.escpos.close();
		}
	}

	private void designLayout() throws Exception {
		this.header();
		switch (helper.properties().type()) {
			case "proforma":
				this.businessAdditional();
				this.documentLegal();
				this.customer();
				this.additional();
				this.items();
				this.amounts();
				this.additionalFooter();
				break;
			case "invoice":
				this.businessAdditional();
				this.documentLegal();
				this.customer();
				this.additional();
				this.items();
				this.amounts();
				this.additionalFooter();
				this.finalMessage();
				this.stringQR();
				this.escpos.pulsePin(PinConnector.Pin_2, 120, 240);
				break;
			case "note":
				this.documentLegal();
				this.customer();
				this.additional();
				break;
			case "command":
				this.productionArea();
				this.documentLegal();
				this.textBackgroundInverted();
				this.additional();
				this.items();
				this.finalMessage();
				break;
			case "precount":
				this.documentLegal();
				this.additional();
				this.items();
				this.amounts();
				break;
			case "extra":
				this.titleExtra();
				this.additional();
				this.items();
				this.amounts();
				break;
			default:
				throw new Exception(String.format("No se pudo imprimir el diseño tipo de documento %s", helper.properties().type()));
		}
		helper.paperCut(escpos);
	}

	private void productionArea() throws Exception {
		if (!this.data.has("productionArea") || !helper.properties().showProductionArea())
			return;
		EscPosWrapper escPosWrapper = new EscPosWrapper(escpos);
		StyleText styleText = helper.styleNormalizeBuilder()
			.align(JustifyAlign.CENTER)
			.bold(true)
			.fontSize(2)
			.build();
		escPosWrapper.printText(this.data.get("productionArea").getAsString(), helper.properties().width(), styleText);
		escPosWrapper.printLine(' ', 1);
	}

	private void header() throws Exception {
		if (helper.properties().type().equalsIgnoreCase("command"))
			return;
		EscPosWrapper escPosWrapper = new EscPosWrapper(escpos);
		JsonObject business = this.data.getAsJsonObject("business");
		if (business.has("comercialDescription")) {
			JsonObject commercialDescription = business.getAsJsonObject("comercialDescription");
			String type = commercialDescription.get("type").getAsString();
			if (type.equalsIgnoreCase("text")) {
				String commercialDescriptionText = commercialDescription.get("value").getAsString();
				var lines = StringUtils.wrapText(commercialDescriptionText, helper.properties().width(), 2);
				StyleText commercialDescriptionStyle = helper.styleNormalizeBuilder()
					.align(JustifyAlign.CENTER)
					.fontSize(FontSize._2)
					.bold(true)
					.build();
				for (String line : lines) {
					escPosWrapper.printText(line, helper.properties().width(), commercialDescriptionStyle);
				}
			}
			if (type.equalsIgnoreCase("img") && helper.properties().logoPath().isPresent()) {
				int imgSize = 290;
				BufferedImage image = ImageUtil.toBufferedImage(helper.properties().logoPath().get());
				BufferedImage resizedImage = ImageUtil.resizeImage(image, imgSize);
				BufferedImage centerImage = ImageUtil.justifyImageToCenter(resizedImage, helper.calcWidthPaperInPx(), imgSize);
				escPosWrapper.bitImage(centerImage, new BitonalThreshold());
			}
		}
		if (business.has("description")) {
			String descriptionText = business.get("description").getAsString();
			var lines = StringUtils.wrapText(descriptionText, helper.properties().width(), 1);
			StyleText descriptionStyle = helper.styleNormalizeBuilder().align(JustifyAlign.CENTER).build();
			for (var line : lines) {
				escPosWrapper.printText(line, helper.properties().width(), descriptionStyle);
			}
		}
	}

	private void businessAdditional() throws Exception {
		var escPosWrapper = new EscPosWrapper(escpos);
		JsonObject business = this.data.getAsJsonObject("business");
		StyleText styleText = helper.styleNormalizeBuilder().align(JustifyAlign.CENTER).build();
		if (business.has("additional")) {
			JsonArray additional = business.get("additional").getAsJsonArray();
			for (JsonElement item : additional) {
				List lines = StringUtils.wrapText(item.getAsString(), helper.properties().width(), 1);
				for (String line : lines) {
					escPosWrapper.printText(line, helper.properties().width(), styleText);
				}
			}
		}
		escPosWrapper.printLine(' ', 1);
	}

	private void documentLegal() throws Exception {
		if (!this.data.has("document"))
			return;
		JsonElement documentObj = this.data.get("document");
		String text;
		if (!(documentObj.isJsonPrimitive())) {
			JsonObject document = documentObj.getAsJsonObject();
			if (helper.properties().type().equalsIgnoreCase("precount") || !document.has("identifier")) {
				text = document.get("description").getAsString();
			} else {
				text = String.format("%s %s", document.get("description").getAsString(), document.get("identifier").getAsString());
			}
		} else {
			String documentId = "";
			if (this.data.has("documentId")) {
				documentId = ": " + this.data.get("documentId").getAsString();
			}
			text = String.format("%s%s", documentObj, documentId);
		}
		FontSize fontWidth = FontSize._1, fontHeight = FontSize._1;
		switch (helper.properties().type()) {
			case "command":
				fontWidth = FontSize._2;
				break;
			case "precount":
				fontWidth = FontSize._2;
				fontHeight = FontSize._2;
				break;
		}
		var lines = StringUtils.wrapText(text, helper.properties().width(), StyleEscPosUtil.valueFontSize(fontWidth));
		StyleText styleText = helper.styleNormalizeBuilder()
			.align(JustifyAlign.CENTER)
			.bold(true)
			.fontWidth(fontWidth)
			.fontHeight(fontHeight)
			.build();
		var escPosWrapper = new EscPosWrapper(escpos);
		for (String line : lines) {
			escPosWrapper.printText(line, helper.properties().width(), styleText);
		}
		if (!helper.properties().type().equalsIgnoreCase("command")) {
			escPosWrapper.printLine(' ', 1);
		}
	}

	private void customer() throws Exception {
		var escPosWrapper = new EscPosWrapper(escpos);
		StyleText styleText = helper.styleNormalizeBuilder()
			.align(JustifyAlign.LEFT)
			.build();
		if (this.data.has("customer")) {
			JsonArray customer = this.data.get("customer").getAsJsonArray();
			for (JsonElement item : customer) {
				List lines = StringUtils.wrapText(item.getAsString(), helper.properties().width(), 1);
				for (String line : lines) {
					escPosWrapper.printText(line, helper.properties().width(), styleText);
				}
			}
		}
		escPosWrapper.printLine(' ', 1);
	}

	private void additional() throws Exception {
		EscPosWrapper escPosWrapper = new EscPosWrapper(escpos);
		if (this.data.has("additional")) {
			JsonArray additional = this.data.get("additional").getAsJsonArray();
			boolean isCommand = helper.properties().type().equalsIgnoreCase("command");
			FontSize fontSize = isCommand ? FontSize._2 : FontSize._1;
			for (int i = 0; i < additional.size(); ++i) {
				JsonElement item = additional.get(i);
				List lines = StringUtils.wrapText(item.getAsString(), helper.properties().width(), StyleEscPosUtil.valueFontSize(fontSize));
				for (String line : lines) {
					StyleTextBuilder styleBuilder = helper.styleNormalizeBuilder();
					if (isCommand) {
						styleBuilder
							.bold(true)
							.fontHeight(1)
							.fontWidth(fontSize)
							.align(JustifyAlign.CENTER);
					} else {
						styleBuilder.align(JustifyAlign.LEFT).fontSize(fontSize);
					}
					escPosWrapper.printText(line, helper.properties().width(), styleBuilder.build());
				}
			}
		}
		escPosWrapper.printLine(' ', 1);
	}

	private void items() throws Exception {
		if (!this.data.has("items") || this.data.get("items").getAsJsonArray().isEmpty())
			return;

		JsonArray items = this.data.get("items").getAsJsonArray();
		boolean isCommand = helper.properties().type().equalsIgnoreCase("command");
		int quantityWidth = 0;
		FontSize fontSize = isCommand ? helper.properties().fontSizeCommand() : FontSize._1;
		int valueFontSize = StyleEscPosUtil.valueFontSize(fontSize);
		int totalWidth = isCommand ? 0 : Default.TOTAL_COLUMN_WIDTH;
		int unitPriceWidth = helper.properties().showUnitPrice() ? Default.UNIT_PRICE_WIDTH : 0;
		int descriptionWidth = helper.properties().width();
		DecimalFormat price = new DecimalFormat("0.00");

		if (items.get(0).getAsJsonObject().has("quantity") && items.get(0).getAsJsonObject().get("quantity").isJsonPrimitive()) {
			quantityWidth = Default.QUANTITY_COLUMN_WIDTH * StyleEscPosUtil.valueFontSize(fontSize);
			descriptionWidth -= (quantityWidth + totalWidth);
		} else {
			descriptionWidth -= totalWidth;
		}

		if (helper.properties().showUnitPrice()) {
			descriptionWidth -= unitPriceWidth;
		}

		EscPosWrapper escPosWrapper = new EscPosWrapper(escpos);
		StyleText quantityStyle = helper.styleNormalizeBuilder().align(JustifyAlign.LEFT).feed(false).build();
		StyleText descriptionStyle = helper.styleNormalizeBuilder().align(JustifyAlign.CENTER).fontSize(1).feed(false).build();
		StyleText unitPriceStyle = helper.styleNormalizeBuilder().align(JustifyAlign.RIGHT).fontSize(1).feed(false).build();
		StyleText totalStyle = helper.styleNormalizeBuilder().align(JustifyAlign.RIGHT).feed(true).build();
		StyleText unitPriceItemStyle = helper.styleNormalizeBuilder()
			.align(JustifyAlign.RIGHT)
			.bold(isCommand)
			.feed(false)
			.build();
		StyleText totalPriceItemStyle = helper.styleNormalizeBuilder()
			.feed(true)
			.align(JustifyAlign.RIGHT)
			.bold(isCommand)
			.build();
		StyleText quantityItemStyle = helper.styleNormalizeBuilder()
			.bold(isCommand)
			.align(JustifyAlign.LEFT)
			.feed(false)
			.fontWidth(fontSize)
			.fontHeight(1)
			.build();
		StyleText commentaryItemStyle = helper.styleNormalizeBuilder()
			.align(isCommand ? JustifyAlign.CENTER : JustifyAlign.LEFT)
			.feed(true)
			.build();

		escPosWrapper.printText("CAN", quantityWidth, quantityStyle);
		escPosWrapper.printText("DESCRIPCIÓN", descriptionWidth, descriptionStyle);
		escPosWrapper.printText("P/U", unitPriceWidth, unitPriceStyle);
		escPosWrapper.printText("TOTAL", totalWidth, totalStyle);
		escPosWrapper.printBoldLine('-', helper.properties().width());

		for (int i = 0; i < items.size(); ++i) {
			JsonObject item = items.get(i).getAsJsonObject();
			JsonElement descriptionObj = item.get("description");
			if (descriptionObj.isJsonArray()) {
				JsonArray description = descriptionObj.getAsJsonArray();
				for (int j = 0; j < description.size(); ++j) {
					if(j == 0 && item.has("quantity") && item.get("quantity").isJsonPrimitive()){
						escPosWrapper.printText(item.get("quantity").getAsString(), quantityWidth, quantityItemStyle);
					}else{
						escPosWrapper.printLine(' ', quantityWidth, quantityItemStyle);
					}
					List lines = StringUtils.wrapText(description.get(j).getAsString(), descriptionWidth, valueFontSize);
					for (int k = 0; k < lines.size(); ++k) {
						String line = lines.get(k);
						StyleTextBuilder itemDescriptionStyleBuilder = helper.styleNormalizeBuilder();
						if (isCommand) {
							itemDescriptionStyleBuilder.bold(true).align(JustifyAlign.CENTER).fontWidth(fontSize).fontHeight(1);
						} else {
							itemDescriptionStyleBuilder.align(JustifyAlign.LEFT).feed(k != 0 || j != 0).fontSize(fontSize);
						}
						escPosWrapper.printText(line, descriptionWidth, itemDescriptionStyleBuilder.build());
						if (j == 0 && k == 0) {
							if (helper.properties().showUnitPrice()) {
								String unitPriceText = "null"; // default
								if (item.has("unitPrice") && !item.get("unitPrice").isJsonNull()) {
									unitPriceText = price.format(item.get("unitPrice").getAsBigDecimal()).concat(" ");
								}
								escPosWrapper.printText(unitPriceText, unitPriceWidth, unitPriceItemStyle);
							}
							String totalPriceItemText = price.format(item.get("totalPrice").getAsBigDecimal());
							escPosWrapper.printText(totalPriceItemText, totalWidth, totalPriceItemStyle);
						}
					}
				}
			} else {
				List lines = StringUtils.wrapText(descriptionObj.getAsString(), descriptionWidth,
					StyleEscPosUtil.valueFontSize(fontSize));
				for (int j = 0; j < lines.size(); ++j) {
					if (j == 0) {
						escPosWrapper.printText(item.get("quantity").getAsString(), quantityWidth, quantityItemStyle);
					} else {
						escPosWrapper.printLine(' ', quantityWidth, helper.noFeedBuilder().build());
					}
					StyleTextBuilder descriptionItemStyleBuilder = helper.styleNormalizeBuilder().bold(isCommand);
					if (isCommand) {
						descriptionItemStyleBuilder.feed(true).fontWidth(fontSize).fontHeight(1).align(JustifyAlign.CENTER);
						escPosWrapper.printText(lines.get(j), descriptionWidth, descriptionItemStyleBuilder.build());
						continue;
					} else {
						descriptionItemStyleBuilder.feed(!item.has("totalPrice")).align(JustifyAlign.LEFT);
						escPosWrapper.printText(lines.get(j), descriptionWidth, descriptionItemStyleBuilder.build());
					}
					if (j == 0 && helper.properties().showUnitPrice()) {
						String unitPriceText = "null"; // default
						if (item.has("unitPrice") && !item.get("unitPrice").isJsonNull()) {
							unitPriceText = price.format(item.get("unitPrice").getAsBigDecimal()).concat(" ");
						}
						escPosWrapper.printText(unitPriceText, unitPriceWidth, unitPriceItemStyle);
					}
					if (j == 0 && item.has("totalPrice")) {
						escPosWrapper.printText(price.format(item.get("totalPrice").getAsBigDecimal()), totalWidth, totalPriceItemStyle);
					} else {
						escPosWrapper.printLine(' ', totalWidth, helper.noFeedBuilder().build());
					}
				}
			}
			if (item.has("commentary") && !item.get("commentary").isJsonNull()) {
				List lines = StringUtils.wrapText(item.get("commentary").getAsString(), descriptionWidth, 1);
				for (String line : lines) {
					escPosWrapper.printLine(' ', quantityWidth, helper.noFeedBuilder().build());
					escPosWrapper.printText(line, descriptionWidth, commentaryItemStyle);
				}
			} else if (isCommand) {
				escPosWrapper.printLine(' ', 1);
			}
		}
		for (int i = 0; i < helper.properties().blankLinesAfterItems(); ++i) {
			escPosWrapper.printLine(' ', 1);
		}
		if (isCommand)
			escPosWrapper.printLine(' ', 1);
		else {
			escPosWrapper.printLine('-', helper.properties().width());
		}
	}

	private void amounts() throws Exception {
		EscPosWrapper escPosWrapper = new EscPosWrapper(escpos);
		StyleText amountsStyle = helper.styleNormalizeBuilder().align(JustifyAlign.RIGHT).build();
		if (this.data.has("amounts")) {
			Map amounts = this.data.getAsJsonObject("amounts").asMap();
			for (Map.Entry amount : amounts.entrySet()) {
				String text = String.format("%s: %s", amount.getKey(), amount.getValue().getAsString());
				escPosWrapper.printText(text, helper.properties().width(), amountsStyle);
			}
			escPosWrapper.printLine('-', helper.properties().width());
		}
		escPosWrapper.printLine(' ', 1);
	}

	private void additionalFooter() throws Exception {
		EscPosWrapper escPosWrapper = new EscPosWrapper(escpos);
		if (this.data.has("additionalFooter")) {
			JsonArray additionalFooter = this.data.get("additionalFooter").getAsJsonArray();
			for (JsonElement item : additionalFooter) {
				List lines = StringUtils.wrapText(item.getAsString(), helper.properties().width(), 1);
				for (String line : lines) {
					escPosWrapper.printText(line, helper.properties().width());
				}
			}
			if (!helper.properties().type().equals("proforma")) {
				escPosWrapper.printLine('-', helper.properties().width());
			}
		}
		escPosWrapper.printLine(' ', 1);
	}

	private void finalMessage() throws Exception {
		EscPosWrapper escPosWrapper = new EscPosWrapper(escpos);
		if (!this.data.has("finalMessage") || this.data.get("finalMessage").isJsonNull()) {
			escPosWrapper.printLine(' ', 1);
			return;
		}
		JsonElement finalMessageObj = this.data.get("finalMessage");
		StyleText finalMessageStyle = helper.styleNormalizeBuilder().align(JustifyAlign.CENTER).build();
		if (finalMessageObj.isJsonArray()) {
			JsonArray finalMessage = finalMessageObj.getAsJsonArray();
			for (JsonElement item : finalMessage) {
				List lines = StringUtils.wrapText(item.getAsString(), helper.properties().width(), 1);
				for (String line : lines) {
					escPosWrapper.printText(line, helper.properties().width(), finalMessageStyle);
				}
			}
		} else {
			List lines = StringUtils.wrapText(finalMessageObj.getAsString(), helper.properties().width(), 1);
			for (String line : lines) {
				escPosWrapper.printText(line, helper.properties().width());
			}
		}
	}

	private void stringQR() throws Exception {
		if (!this.data.has("stringQR") || this.data.get("stringQR").isJsonNull()) {
			return;
		}
		String stringQr = this.data.get("stringQR").toString();
		EscPosWrapper escPosWrapper = new EscPosWrapper(this.escpos);
		if (!helper.properties().nativeQR()) {
			int sizeQR = 200;
			BufferedImage image = QRCodeGenerator.render(stringQr, sizeQR);
			BufferedImage centerImage = ImageUtil.justifyImageToCenter(image, helper.calcWidthPaperInPx(), sizeQR);
			escPosWrapper.bitImage(centerImage, new BitonalOrderedDither());
		} else {
			escPosWrapper.printLine(' ', 1);
			escPosWrapper.standardQR(stringQr);
		}
	}

	private void titleExtra() throws Exception {
		EscPosWrapper escPosWrapper = new EscPosWrapper(escpos);
		if (!this.data.has("titleExtra")) {
			escPosWrapper.printLine('-', helper.properties().width());
			return;
		}
		JsonObject titleExtra = this.data.getAsJsonObject("titleExtra");
		StyleTextBuilder titleStyleBuilder = helper.styleNormalizeBuilder().align(JustifyAlign.CENTER).fontSize(2).bold(true);
		escPosWrapper.printText(titleExtra.get("title").getAsString(), helper.properties().width(), titleStyleBuilder.build());
		escPosWrapper.printText(titleExtra.get("subtitle").getAsString(), helper.properties().width(), titleStyleBuilder.bold(false).build());
		escPosWrapper.printLine(' ', 1);
	}

	private void textBackgroundInverted() throws Exception {
		if (this.data.has("textBackgroundInverted") && !this.data.get("textBackgroundInverted").isJsonNull()) {
			EscPosWrapper escPosWrapper = new EscPosWrapper(escpos);
			boolean supportBackgroundInverted = helper.properties().backgroundInverted();
			String text = String.format(" %s ", this.data.get("textBackgroundInverted").getAsString());
			StyleText styleText = helper.styleNormalizeBuilder()
				.align(JustifyAlign.CENTER)
				.bold(!supportBackgroundInverted)
				.pad(supportBackgroundInverted ? ' ' : '*')
				.bgInverted(supportBackgroundInverted)
				.build();
			escPosWrapper.printText(text, helper.properties().width(), styleText);
			escPosWrapper.printLine(' ', helper.properties().width());
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy