// Chromis POS - The New Face of Open Source POS
// Copyright (c) 2015
// http://www.chromis.co.uk
//
// This file is part of Chromis POS
//
// Chromis POS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Chromis POS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Chromis POS. If not, see <http://www.gnu.org/licenses/>.
package uk.chromis.pos.ticket;
import java.io.ByteArrayInputStream;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import uk.chromis.basic.BasicException;
import uk.chromis.data.loader.DataRead;
import uk.chromis.data.loader.LocalRes;
import uk.chromis.data.loader.SerializableRead;
import uk.chromis.format.Formats;
import uk.chromis.pos.customers.CustomerInfoExt;
import uk.chromis.pos.forms.AppConfig;
import uk.chromis.pos.payment.PaymentInfo;
import uk.chromis.pos.payment.PaymentInfoMagcard;
import uk.chromis.pos.util.StringUtils;
/**
*
* @author adrianromero
*/
public final class TicketInfo implements SerializableRead, Externalizable {
private static final long serialVersionUID = 2765650092387265178L;
private static final DateFormat m_dateformat = new SimpleDateFormat("hh:mm");
private String m_sHost;
private String m_sId;
private TicketType tickettype;
private int m_iTicketId;
private int m_iPickupId;
private java.util.Date m_dDate;
private Properties attributes;
private UserInfo m_User;
private Double multiply;
private CustomerInfoExt m_Customer;
private String m_sActiveCash;
private List<TicketLineInfo> m_aLines;
private List<PaymentInfo> payments;
private List<TicketTaxInfo> taxes;
private CouponSet m_CouponLines;
private final String m_sResponse;
private String loyaltyCardNumber;
private Boolean oldTicket;
private Boolean m_sharedticket;
private UserInfo m_sharedticketUser;
private String m_nosc;
private static String Hostname;
public static void setHostname(String name) {
Hostname = name;
}
public static String getHostname() {
return Hostname;
}
/**
* Creates new TicketModel
*/
public TicketInfo() {
m_sId = UUID.randomUUID().toString();
tickettype = TicketType.NORMAL;
m_iTicketId = 0; // incrementamos
m_dDate = new Date();
attributes = new Properties();
m_User = null;
m_Customer = null;
m_sActiveCash = null;
m_aLines = new ArrayList<>();
m_CouponLines = new CouponSet();
payments = new ArrayList<>();
taxes = null;
m_sResponse = null;
oldTicket = false;
multiply = 0.0;
m_sharedticket = false;
m_nosc = "0";
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(m_sId);
out.writeInt(tickettype.id);
out.writeInt(m_iTicketId);
out.writeObject(m_Customer);
out.writeObject(m_dDate);
out.writeObject(m_User);
out.writeObject(attributes);
out.writeObject(m_aLines);
out.writeObject(m_CouponLines);
out.writeObject(m_nosc);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
m_sId = (String) in.readObject();
tickettype = TicketType.get(in.readInt());
m_iTicketId = in.readInt();
m_Customer = (CustomerInfoExt) in.readObject();
m_dDate = (Date) in.readObject();
m_User = (UserInfo) in.readObject();
attributes = (Properties) in.readObject();
m_aLines = (List<TicketLineInfo>) in.readObject();
m_CouponLines = (CouponSet) in.readObject();
m_nosc = (String) in.readObject();
m_sActiveCash = null;
payments = new ArrayList<>();
taxes = null;
m_sharedticketUser = m_User;
}
/**
*
* @param dr
* @throws BasicException
*/
@Override
public void readValues(DataRead dr) throws BasicException {
m_sId = dr.getString(1);
tickettype = TicketType.get(dr.getInt(2));
m_iTicketId = dr.getInt(3);
m_dDate = dr.getTimestamp(4);
m_sActiveCash = dr.getString(5);
try {
byte[] img = dr.getBytes(6);
if (img != null) {
attributes.loadFromXML(new ByteArrayInputStream(img));
}
} catch (IOException e) {
}
m_User = new UserInfo(dr.getString(7), dr.getString(8));
m_Customer = new CustomerInfoExt(dr.getString(9));
m_aLines = new ArrayList<>();
try {
m_CouponLines = (CouponSet) dr.getObject(10);
} catch (BasicException e) {
// Ignore error - may be editing a ticket saved pre-coupon support
m_CouponLines = new CouponSet();
}
payments = new ArrayList<>();
taxes = null;
m_sharedticketUser = m_User;
}
/**
*
* @return
*/
public TicketInfo copyTicket() {
TicketInfo t = new TicketInfo();
t.tickettype = tickettype;
t.m_iTicketId = m_iTicketId;
t.m_dDate = m_dDate;
t.m_sActiveCash = m_sActiveCash;
t.attributes = (Properties) attributes.clone();
t.m_User = m_User;
t.m_Customer = m_Customer;
t.m_aLines = new ArrayList<>();
for (TicketLineInfo l : m_aLines) {
t.m_aLines.add(l.copyTicketLine());
}
t.m_CouponLines = new CouponSet();
t.m_CouponLines.copyAll(m_CouponLines);
t.refreshLines();
t.payments = new LinkedList<>();
for (PaymentInfo p : payments) {
t.payments.add(p.copyPayment());
}
t.oldTicket = oldTicket;
t.m_nosc = m_nosc;
// taxes are not copied, must be calculated again.
return t;
}
public Double getDiscount() {
Double discount = null;
if (m_Customer != null) {
discount = m_Customer.getDiscount();
}
if (discount == null) {
discount = 0.0;
}
return discount;
}
private Double applyDiscount(Double value) {
if (value != null && value > 0.0) {
value = value - (value * getDiscount());
}
return value;
}
/**
*
* @return
*/
public String getId() {
return m_sId;
}
/**
*
* @return
*/
public TicketType getTicketType() {
return tickettype;
}
/**
*
* @param tickettype
*/
public void setTicketType(final TicketType _tickettype) {
this.tickettype = _tickettype;
}
/**
*
* @return
*/
public int getTicketId() {
return m_iTicketId;
}
/**
*
* @param iTicketId
*/
public void setTicketId(int iTicketId) {
m_iTicketId = iTicketId;
// refreshLines();
}
/**
*
* @param iTicketId
*/
public void setPickupId(int iTicketId) {
m_iPickupId = iTicketId;
}
/**
*
* @return
*/
public int getPickupId() {
return m_iPickupId;
}
/**
*
* @param info
* @return
*/
public String getName(Object info) {
StringBuilder name = new StringBuilder();
if (m_User != null) {
name.append(m_User.getName());
name.append(" - ");
}
if (info == null) {
if (m_iTicketId == 0) {
name.append("(").append(m_dateformat.format(m_dDate)).append(" ").append(Long.toString(m_dDate.getTime() % 1000)).append(")");
} else {
name.append(Integer.toString(m_iTicketId));
}
} else {
name.append(info.toString());
}
if (getCustomerId() != null) {
name.append(" - ");
name.append(m_Customer.toString());
Double discount = getDiscount();
if (discount > 0.0) {
name.append(" -");
name.append(Formats.PERCENT.formatValue(discount));
}
}
return name.toString();
}
public String getName(Object info, String pickupID) {
StringBuilder name = new StringBuilder();
// if (m_User != null) {
name.append(pickupID);
name.append(" - ");
// }
if (info == null) {
if (m_iTicketId == 0) {
name.append("(").append(m_dateformat.format(m_dDate)).append(" ").append(Long.toString(m_dDate.getTime() % 1000)).append(")");
} else {
name.append(Integer.toString(m_iTicketId));
}
} else {
name.append(info.toString());
}
if (getCustomerId() != null) {
name.append(" - ");
name.append(m_Customer.toString());
Double discount = getDiscount();
if (discount > 0.0) {
name.append(" -");
name.append(Formats.PERCENT.formatValue(discount));
}
}
return name.toString();
}
public String getName() {
return getName(null);
}
public java.util.Date getDate() {
return m_dDate;
}
public void setDate(java.util.Date dDate) {
m_dDate = dDate;
}
public String getNoSC() {
return m_nosc;
}
public void setNoSC(String value) {
m_nosc = value;
}
public UserInfo getUser() {
return m_User;
}
public UserInfo getSharedTicketUser() {
return m_sharedticketUser;
}
public void setUser(UserInfo value) {
m_User = value;
}
public CustomerInfoExt getCustomer() {
return m_Customer;
}
public void setCustomer(CustomerInfoExt value) {
m_Customer = value;
}
public String getCustomerId() {
if (m_Customer == null) {
return null;
} else {
return m_Customer.getId();
}
}
public String getTransactionID() {
return (getPayments().size() > 0)
? (getPayments().get(getPayments().size() - 1)).getTransactionID()
: StringUtils.getCardNumber(); //random transaction ID
}
public String getReturnMessage() {
return ((getPayments().get(getPayments().size() - 1)) instanceof PaymentInfoMagcard)
? ((PaymentInfoMagcard) (getPayments().get(getPayments().size() - 1))).getReturnMessage()
: LocalRes.getIntString("button.ok");
}
public void setActiveCash(String value) {
m_sActiveCash = value;
}
public String getActiveCash() {
return m_sActiveCash;
}
public String getProperty(String key) {
return attributes.getProperty(key);
}
public String getProperty(String key, String defaultvalue) {
return attributes.getProperty(key, defaultvalue);
}
public void setProperty(String key, String value) {
attributes.setProperty(key, value);
}
public Properties getProperties() {
return attributes;
}
public TicketLineInfo getLine(int index) {
return m_aLines.get(index);
}
public void addLine(TicketLineInfo oLine) {
oLine.setTicket(m_sId, m_aLines.size());
m_aLines.add(oLine);
}
public void addCouponLine(String id, int line, String text) {
m_CouponLines.add(id, line, text);
}
public void removeCouponLine(String id, int line) {
m_CouponLines.remove(id, line);
}
public void removeCoupon(String id) {
if (id == null) {
// Remove all coupons
m_CouponLines.clear();
} else {
m_CouponLines.remove(id);
}
}
public int checkAndAddLine(TicketLineInfo oLine, boolean flag) {
// returns index of product in the ticket list or -1 if new product
if (m_aLines.size() == 0 || !flag) {
oLine.setTicket(m_sId, m_aLines.size());
m_aLines.add(oLine);
return -1;
} else {
int size = m_aLines.size();
for (int i = 0; i < size; i++) {
TicketLineInfo temp = m_aLines.get(i);
if ((temp.getProductID().equals(oLine.getProductID())) && oLine.getProductAttSetId() == null) {
m_aLines.get(i).setMultiply(m_aLines.get(i).getMultiply() + oLine.getMultiply());
return i;
}
}
oLine.setTicket(m_sId, m_aLines.size());
m_aLines.add(oLine);
return -1;
}
}
public void insertLine(int index, TicketLineInfo oLine) {
m_aLines.add(index, oLine);
refreshLines();
}
public void setLine(int index, TicketLineInfo oLine) {
oLine.setTicket(m_sId, index);
m_aLines.set(index, oLine);
}
public void removeLine(int index) {
m_aLines.remove(index);
refreshLines();
}
private void refreshLines() {
for (int i = 0; i < m_aLines.size(); i++) {
getLine(i).setTicket(m_sId, i);
}
}
public int getLinesCount() {
return m_aLines.size();
}
public double getArticlesCount() {
double dArticles = 0.0;
TicketLineInfo oLine;
for (Iterator<TicketLineInfo> i = m_aLines.iterator(); i.hasNext();) {
oLine = i.next();
dArticles += oLine.getMultiply();
}
return dArticles;
}
public double getSubTotal() {
double sum = 0.0;
for (TicketLineInfo line : m_aLines) {
sum += line.getSubValue();
}
return sum;
}
public double getTax() {
double sum = 0.0;
if (hasTaxesCalculated()) {
for (TicketTaxInfo tax : taxes) {
sum += tax.getTax(); // Taxes are already rounded...
}
} else {
for (TicketLineInfo line : m_aLines) {
sum += line.getTax();
}
}
return sum;
}
public double getTotal() {
return getSubTotal() + getTax();
}
public double getTotalPaid() {
double sum = 0.0;
for (PaymentInfo p : payments) {
if (!"debtpaid".equals(p.getName())) {
sum += p.getTotal();
}
}
return sum;
}
public double getTotalChange() {
double sum = 0.0;
for (PaymentInfo p : payments) {
if (!"debtpaid".equals(p.getName())) {
sum += p.getChange();
}
}
return sum;
}
public double getChange() {
return getTotalChange();
}
public double getTotalTendered() {
double sum = 0.0;
for (PaymentInfo p : payments) {
if (!"debtpaid".equals(p.getName())) {
sum += p.getTendered();
}
}
return sum;
}
public double getTendered() {
return getTotalTendered();
}
public List<String> getCouponLines() {
return m_CouponLines.getCouponLines();
}
public List<TicketLineInfo> getLines() {
return m_aLines;
}
public void setLines(List<TicketLineInfo> l) {
m_aLines = l;
}
public List<PaymentInfo> getPayments() {
return payments;
}
public void setPayments(List<PaymentInfo> l) {
payments = l;
}
public void resetPayments() {
payments = new ArrayList<>();
}
public List<TicketTaxInfo> getTaxes() {
return taxes;
}
public boolean hasTaxesCalculated() {
return taxes != null;
}
public void setTaxes(List<TicketTaxInfo> l) {
taxes = l;
}
public void resetTaxes() {
taxes = null;
}
public TicketTaxInfo getTaxLine(TaxInfo tax) {
for (TicketTaxInfo taxline : taxes) {
if (tax.getId().equals(taxline.getTaxInfo().getId())) {
return taxline;
}
}
return new TicketTaxInfo(tax);
}
public TicketTaxInfo[] getTaxLines() {
Map<String, TicketTaxInfo> m = new HashMap<>();
TicketLineInfo oLine;
for (Iterator<TicketLineInfo> i = m_aLines.iterator(); i.hasNext();) {
oLine = i.next();
TicketTaxInfo t = m.get(oLine.getTaxInfo().getId());
if (t == null) {
t = new TicketTaxInfo(oLine.getTaxInfo());
m.put(t.getTaxInfo().getId(), t);
}
t.add(oLine.getSubValue());
}
Collection<TicketTaxInfo> avalues = m.values();
return avalues.toArray(new TicketTaxInfo[avalues.size()]);
}
public String printId() {
String receiptSize = (AppConfig.getInstance().getProperty("till.receiptsize"));
String receiptPrefix = (AppConfig.getInstance().getProperty("till.receiptprefix"));
if (m_iTicketId > 0) {
String tmpTicketId = Integer.toString(m_iTicketId);
if (receiptSize == null || (Integer.parseInt(receiptSize) <= tmpTicketId.length())) {
if (receiptPrefix != null) {
tmpTicketId = receiptPrefix + tmpTicketId;
}
return tmpTicketId;
}
while (tmpTicketId.length() < Integer.parseInt(receiptSize)) {
tmpTicketId = "0" + tmpTicketId;
}
if (receiptPrefix != null) {
tmpTicketId = receiptPrefix + tmpTicketId;
}
return tmpTicketId;
} else {
return "";
}
}
public String printDate() {
return Formats.TIMESTAMP.formatValue(m_dDate);
}
public String printUser() {
return m_User == null ? "" : m_User.getName();
}
public String getHost() {
return m_sHost;
}
public String printHost() {
return StringUtils.encodeXML(m_sHost);
}
public void clearCardNumber() {
loyaltyCardNumber = null;
}
public void setLoyaltyCardNumber(String cardNumber) {
loyaltyCardNumber = cardNumber;
}
public String getLoyaltyCardNumber() {
return (loyaltyCardNumber);
}
public String printCustomer() {
return m_Customer == null ? "" : m_Customer.getName();
}
public String printArticlesCount() {
return Formats.DOUBLE.formatValue(getArticlesCount());
}
public String printSubTotal() {
return Formats.CURRENCY.formatValue(getSubTotal());
}
public String printTax() {
return Formats.CURRENCY.formatValue(getTax());
}
public String printTotal() {
return Formats.CURRENCY.formatValue(getTotal());
}
public String printTotalPaid() {
return Formats.CURRENCY.formatValue(getTotalPaid());
}
public String printTendered() {
return Formats.CURRENCY.formatValue(getTendered());
}
public String printOriginalUser() {
if (getSharedTicketUser() == null) {
return "";
}
return getSharedTicketUser().getName();
}
public String printChange() {
return Formats.CURRENCY.formatValue(getTendered() - getTotal());
}
public String VoucherReturned() {
return Formats.CURRENCY.formatValue(getTotalPaid() - getTotal());
}
public boolean getOldTicket() {
return (oldTicket);
}
public void setSharedTicket(Boolean shared) {
m_sharedticket = shared;
}
public boolean isSharedTicket() {
return (m_sharedticket);
}
public void setdDate(java.util.Date m_date) {
m_dDate = m_date;
}
public java.util.Date getdDate() {
return m_dDate;
}
/**
*
* @param otState
*/
public void setOldTicket(Boolean otState) {
oldTicket = otState;
}
}