今天是个好日子,TaxCore(POS软件)备案指北
POS软件是什么?你好意思吗,还在用老掉牙的Winform。
关于POS
销售终端——POS(point of sale)是一种多功能终端,把它安装在信用卡的特约商户和受理网点中与计算机联成网络,就能实现电子资金自动转账,它具有支持消费、预授权、余额查询和转账等功能,使用起来安全、快捷、可靠。
POS软件大都长这样子:
不好意思了,我没有专门去收集POS软件的UI界面。感兴趣的朋友可以去澳大利亚知名POS软件供应商IDEALPOS的官网去围观:
前言
好久以前就想写这篇文章了,一是想要证明我还在程序员队伍里苟延残喘。二是这样的文章我从来就没看见过,写出来万一帮到其他人了呢。今天早上我查看请求的状态时豁然发现已经通过平台的审核了,接下来就是区域的审核:我们公司在FEIJI和SAMOA都有门店。
目前TaxCore提供的税务平台有四个国家(地区)在用:Samoa ,Fiji,USA, WA.目前TaxCore上备案通过的也没几家公司,我知道的就只要上面提到的澳大利亚IDEALPOS。
我的软件界面有参考它。在国内税务发票是使用针式打印机,套打发票,而国外的发票要求没这么高,用普通的热敏打印机打印就可以了,因为发票是可以在TaxCore的网站上面看到的。所以不能长期保存也没有问题。下面展示一张财务发票:TaxCore: Invoice Verification - TaxCore,点击一下页面的Journal超链接能看到财政发票的原始样子,大概就是这样子:

对于纳税人来说可以通过扫描发票上的二维码进行在线查看。对于商户来说,也可以进入到自己所在区域的税所的门户网站后台查看每一张发票,这是TaxCore的全球的沙盒环境的门户:TaxCore | Log off 。财政发票的从开始到结束部分是不运行有任何改动的。但商家可以在头尾加一点自己的东西比如:

TaxCore的审核是我见过最认真细致的,对发票的要求细致得很。我们软件来来回回经过十几轮审核修好终于才通过了。下面展示TaxCore对发票的要求:

乍一看,这基本上是不可能完成的任务吧,全英文的在线文档,没有人带,还好官方有个工单系统,有问题可以在上面提问,会得到很及时的很友好的回复(由于一般有时区的差异,工作时间不一样不要要求马上有答复)。关于官方的帮助文档的地址请点击这里:TaxCore - Help Viewer (revenue.gov.ws)
指北的正文
<!DOCTYPE html>
<html>
<head>
<title>Online POS</title>
<meta charset="utf-8">
</head>
<body>
<h1>Online POS</h1>
<label for="invoiceRequest">Invoice request json</label>
<textarea id="invoiceRequest" cols="100" rows="30" style="display:block"></textarea>
<label for="taxcore_sign_element">Send Invoice Request:</label>
<!--TaxCore HTML element-->
<button id="taxcore_sign_element"
data-taxcore-vsdc-url=" https://vsdc.sandbox.taxcore.online/"
data-taxcore-input-id="invoiceRequest"
data-taxcore-output-id="results"
data-taxcore-invoice-request=""
data-taxcore-debug="true"
data-taxcore-signed-invoice-response="">Sign Invoice</button>
<label for="results">Received Signed Invoice:</label>
<textarea readonly id="results" cols="100" rows="30"></textarea>
<!-- TAXCORE.JS -->
<script src=" https://vsdc.sandbox.taxcore.online/onlinepos/v1/taxcore.min.js"></script>
<!-- Custom script at Online POS -->
<script>
document.getElementById("invoiceRequest").innerHTML =
JSON.stringify(CreateExampleInvoiceRequest(), undefined, 4); document.getElementById("taxcore_sign_element").dataset.taxcoreInvoiceRequest =
JSON.stringify(CreateExampleInvoiceRequest()); // Listen to messages from TaxCore
window.onmessage = function (e) {
console.log(e.data);
} function CreateExampleInvoiceRequest() {
var invoiceRequest = {
"DateAndTimeOfIssue": "2017-08-31T13:28:02.433Z",
"Cashier": "John",
"BD": null,
"BuyerCostCenterId": null,
"IT": "Normal",
"TT": "Sale",
"PaymentType": "Card",
"InvoiceNumber": "31082017-2",
"ReferentDocumentNumber": null,
"PAC": null,
"Options": {
"OmitTextualRepresentation": 0,
"OmitQRCodeGen": 0
},
"Items": [
{
"GTIN": null,
"Name": "Book",
"Quantity": 1,
"Labels": [
"A"
],
"TotalAmount": 50
}
]
}; return invoiceRequest;
}
</script>
</body>
</html>
在国内是不存在网络问题的,所以官方提供了HTML在线POS的示例代码。那么我认为有必要提一下为什么最终我选择了用Winform来做这个客户端程序。第一我有多年的CS程序开发经验,在这里3G和4G都满如蜗牛一样的网络条件下我首先想到的是自动实现离线和在线模式切换,先把交易数据存在本地的Sqlite中,一旦网络可用才上传到服务器,而且针对离线交易不能打印在线的财政发票的情况下TaxCore提供了半连接模式可以使用智能卡存储交易数据,一旦网络恢复则从卡里读取数据再上传,提供了一种本地审核的方式,就是离线可以打印财政发票。由于我对WPF等技术不太熟练,综合考虑于是就使用了WinForm来开发客户端程序。下面贴一点WinForm发起发票请求的代码:
/// <summary>
/// 发起联网发票请求
/// </summary>
/// <param name="bill">订单</param>
public void RequestNormalInvoice(OrderTableEntity bill)
{
#region 构建请求json
TaxCoreBobyRequest request = new TaxCoreBobyRequest();
request.Cashier = bill.casher;
if (CurrentMemberObj != null)
request.BD = string.IsNullOrEmpty(CurrentMemberObj.Buyer_Tin) == true ? null : CurrentMemberObj.Buyer_Tin;
else
request.BD = null;
request.BuyerCostCenterId = null;
request.IT = "Normal";
request.TT = "Sale";
request.InvoiceNumber = bill.orderNo;
request.ReferentDocumentNumber = null;
request.PAC = $"{ConfigObj.PAC}";
var s1 = new BaseRepository<BillPayDetailEntityTable>();
var s2 = new BaseRepository<BillConsumeDetailEntityTable>();
var s3 = new BaseRepository<Payment_method_tableEntity>();
var list1 = s1.GetList(p => p.order_No == bill.orderNo);
var list2 = s2.GetList(p => p.order_No == bill.orderNo);
List<GoodsItem> items = new List<GoodsItem>();
var goodsSvr = new BaseRepository<GoodsTableEntity>();
#region 商品明细
foreach (var item in list2)
{
var goods = goodsSvr.GetFirst(g => g.goodsNo == item.goods_No);
items.Add(new GoodsItem
{
GTIN = null,
Name = item.goods_Name,
Quantity = item.qty,
UnitPrice = item.sale_price - item.discountAmount,
TotalAmount = item.qty * (item.sale_price - item.discountAmount),
Labels = new string[]
{
goods == null ? ConfigObj.MISCELLANEOUS_Rate_Label : goods.taxLabels
}
});
}
#endregion
request.Items = items;
var pInfo = s3.GetList(p => p.pm_Id == list1.FirstOrDefault().payment_method).FirstOrDefault();
if (pInfo.TaxcoreName != pInfo.pm_Name)
request.PaymentType = pInfo.TaxcoreName;
else
request.PaymentType = pInfo.pm_Name;
#endregion
string invoiceRequest = JsonConvert.SerializeObject(request);
var httpContent = new StringContent(invoiceRequest, Encoding.UTF8, "application/json");
HttpClient client;
WebRequestHandler handler;
GetClientAndHandler(out handler, out client);
var response = client.PostAsync($"api/Sign/SignInvoice", httpContent).Result;
if (response.StatusCode == HttpStatusCode.OK)
{
var svr = new BaseRepository<OrderTableEntity>();
bool b = invoiceRequest.Contains("'");
if (b)
invoiceRequest = invoiceRequest.Replace("'", " ");
string cmd = $"update orders set fiscalInvoiceRequest='{invoiceRequest}' where orderNo='{bill.orderNo}'";
svr.Context.Ado.ExecuteCommand(cmd);
var jsonString = response.Content.ReadAsStringAsync();
jsonString.Wait();
var invoiceResponse = jsonString.Result;
var responseObj = JsonConvert.DeserializeObject<TaxCoreResponse>(invoiceResponse);
orderTableEntity = bill;
PrintNormalInvoice(responseObj);
responseObj.VerificationQRCode = "";
responseObj.ID = "";
responseObj.S = "";
responseObj.Journal = "";
string cmd_sql = $"update orders set UploadDateTime=null,fiscalInvoiceResponse='{JsonConvert.SerializeObject(responseObj)}' where orderNo='{bill.orderNo}'";
svr.Context.Ado.ExecuteCommand(cmd_sql);
}
else
{
MessageTip.ShowError($"Failed to request invoice:[{response.StatusCode}]");
throw new Exception($"Failed to request invoice:[{response.StatusCode}]");
}
} /// <summary>
/// 请求地址赋值
/// </summary>
/// <param name="handler"></param>
/// <param name="client"></param>
public void GetClientAndHandler(out WebRequestHandler handler, out HttpClient client)
{
handler = CreateWebRequestHandler();
client = new HttpClient(handler);
client.BaseAddress = new Uri($"{ConfigObj.RequstBaseURL}");
client.DefaultRequestHeaders.Accept.Clear();
}
/// <summary>
/// 请求加入证书
/// </summary>
/// <returns></returns>
private WebRequestHandler CreateWebRequestHandler()
{
var handler = new WebRequestHandler();
var cert = GetClientCertificate();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ClientCertificates.Add(cert);
return handler;
}
/// <summary>
/// 读取证书
/// </summary>
/// <returns></returns>
private X509Certificate2 GetClientCertificate()
{
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
//store.Open(OpenFlags.ReadWrite);
string certName = $"{ConfigObj.InvoiceCertificateName}";
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
var certificates = store.Certificates;
foreach (X509Certificate2 cert in certificates)
{
if (cert.Subject.Contains(certName))
{
return cert;
}
}
return null;
}
关于打印的代码就有点冗长了,请无视我的复制和粘帖运用得如此炉火纯青。
/// <summary>
/// 发票绘制
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void PdInvoice_PrintPage(object sender, PrintPageEventArgs e)
{
string[] journal = currentResponse.Journal.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
string pos_time = journal[9].Replace("POS Time: ", "");
if (!string.IsNullOrEmpty(orderTableEntity.member_No))
pos_time = journal[10].Replace("POS Time: ", "");
var s1 = new BaseRepository<BillConsumeDetailEntityTable>();
var s2 = new BaseRepository<BillPayDetailEntityTable>();
var list1 = s1.GetList(o => o.order_No == orderTableEntity.orderNo);
var list2 = s2.GetList(o => o.order_No == orderTableEntity.orderNo);
int right_space = 32;
e.Graphics.Clear(Color.White);
Rectangle rect = new Rectangle(0, 0, 300, 360);
#region StringFormat
StringFormat sf_center = new StringFormat();
sf_center.Alignment = StringAlignment.Center;
sf_center.LineAlignment = StringAlignment.Center;
StringFormat sf_left = new StringFormat();
sf_left.Alignment = StringAlignment.Near;
sf_left.LineAlignment = StringAlignment.Center;
StringFormat sf_right = new StringFormat();
sf_right.Alignment = StringAlignment.Far;
sf_right.LineAlignment = StringAlignment.Center;
#endregion
Font tipsFont = new Font("微软雅黑", 9F, FontStyle.Bold);
Font txtFont = new Font("微软雅黑", 9F);
e.Graphics.DrawString($"{merchantStoreEntity.name}", tipsFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_center);
rect.Y += 20;
e.Graphics.DrawString($"===========================================", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
rect.Y += 20;
e.Graphics.DrawString($"PH#:{merchantStoreEntity.phone} MOB#:{merchantStoreEntity.mobile}", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_center);
if (!string.IsNullOrEmpty(merchantStoreEntity.store_advertising))
{
rect.Y += 20;
e.Graphics.DrawString($"{merchantStoreEntity.store_advertising}", tipsFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_center);
}
rect.Y += 20;
e.Graphics.DrawString($"========= FISCAL INVOICE ===============", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
rect.Y += 20;
e.Graphics.DrawString($"TIN:", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString(currentResponse.TIN, txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
rect.Y += 20;
e.Graphics.DrawString($"Company:", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString($"{currentResponse.BusinessName}", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
rect.Y += 20;
e.Graphics.DrawString($"Store:", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString($"{merchantStoreEntity.name}", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
rect.Y += 20;
e.Graphics.DrawString($"Address:", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString($"{currentResponse.Address}", txtFont, Brushes.Black, new Rectangle(42, rect.Y, rect.Width - 76, 40), sf_right);
rect.Y += 40;
e.Graphics.DrawString($"District:", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString($"{currentResponse.District}", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
rect.Y += 20;
e.Graphics.DrawString($"Cashier TIN:", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString($"{CashierFlowContext.Instance.CurrentEmployee.employeeName}", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
rect.Y += 20;
e.Graphics.DrawString($"POS Number:", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString($"{orderTableEntity.orderNo}", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
rect.Y += 20;
e.Graphics.DrawString($"POS Time:", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString(pos_time.Trim(), txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
if (!string.IsNullOrEmpty(orderTableEntity.member_No))
{
rect.Y += 20;
e.Graphics.DrawString($"Buyer TIN:", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString($"{orderTableEntity.member_No}", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
}
rect.Y += 20;
e.Graphics.DrawString($"-----------------NORMAL SALE--------------------", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
rect.Y += 20;
e.Graphics.DrawString($"Items", txtFont, Brushes.Black, new Rectangle(4, rect.Y, rect.Width, 20), sf_center);
rect.Y += 20;
e.Graphics.DrawString($"===========================================", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
rect.Y += 18;
e.Graphics.DrawString($"Name Price Qty. Total ", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
rect.Y += 16;
var goodsSvr = new BaseRepository<GoodsTableEntity>();
foreach (var detailRow in list1)
{
var goods = goodsSvr.GetFirst(g => g.goodsNo == detailRow.goods_No);
string label = goods == null ? ConfigObj.MISCELLANEOUS_Rate_Label : goods.taxLabels;
e.Graphics.DrawString($"{detailRow.goods_Name} ({label})", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString($"{detailRow.sale_price.ToString("C2").Substring(1)}", txtFont, Brushes.Black, new Rectangle(rect.Width / 2 - 86, rect.Y + 16, rect.Width, 20), sf_left);
e.Graphics.DrawString($"{detailRow.qty}", txtFont, Brushes.Black, new Rectangle(rect.Width / 2 - 8, rect.Y + 16, rect.Width, 20), sf_left);
e.Graphics.DrawString($"{detailRow.amount.ToString("C2").Substring(1)}", txtFont, Brushes.Black, new Rectangle(0, rect.Y + 16, rect.Width - right_space - 8, 20), sf_right);
rect.Y += 34;
}
e.Graphics.DrawString($"Total Purchase:", tipsFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString($"{orderTableEntity.payAmount.ToString("C2").Substring(1)}", tipsFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
rect.Y += 20;
var service = new BaseRepository<Payment_method_tableEntity>();
var p = service.GetFirst(pm => pm.pm_Id == list2.FirstOrDefault().payment_method);
e.Graphics.DrawString($"Payment Method:", tipsFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
if (p.TaxcoreName != p.pm_Name)
e.Graphics.DrawString(p.TaxcoreName, tipsFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
else
e.Graphics.DrawString($"{p.pm_Name}", tipsFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
rect.Y += 20;
e.Graphics.DrawString($"===========================================", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
rect.Y += 18;
e.Graphics.DrawString($"Label Name Rate ", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString(" Tax ", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
rect.Y += 20;
foreach (var rate in currentResponse.TaxItems)
{
e.Graphics.DrawString($"{rate.Label} {rate.CategoryName} {rate.Rate}% ", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString($"{rate.Amount.ToString("C2").Substring(1)} ", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
rect.Y += 20;
}
e.Graphics.DrawString($"--------------------------------------------------", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
rect.Y += 20;
e.Graphics.DrawString($"Total Tax:", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString($"{currentResponse.TaxItems.Sum(t => t.Amount).ToString("C2").Substring(1)}", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
rect.Y += 20;
e.Graphics.DrawString($"===========================================", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
rect.Y += 20;
e.Graphics.DrawString($"SDC Time:", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
string dt = Convert.ToDateTime(currentResponse.DT).ToString("dd/MM/yyyy HH:mm:ss");
if (ConfigObj.RequstBaseURL.Contains("sandbox"))
{
dt = Convert.ToDateTime(currentResponse.DT.AddHours(-12)).ToString("dd/MM/yyyy HH:mm:ss");//.ToString("dd/MM/yyyy HH:mm:ss");
}
e.Graphics.DrawString($"{dt}", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
rect.Y += 20;
e.Graphics.DrawString($"SDC Invoice No: ", new Font("微软雅黑", 8.2F), Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_left);
e.Graphics.DrawString($"{currentResponse.IN}", new Font("微软雅黑", 8.2F), Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
rect.Y += 20;
e.Graphics.DrawString($"Invoice Counter: ", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_left);
e.Graphics.DrawString($"{currentResponse.IC}", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
rect.Y += 20;
e.Graphics.DrawString($"===========================================", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
rect.Y += 20;
byte[] bytes = Convert.FromBase64String(currentResponse.VerificationQRCode);
MemoryStream memStream = new MemoryStream(bytes);
Image mImage = Image.FromStream(memStream);
e.Graphics.DrawImage(mImage, new Rectangle(8, rect.Y, 266, 266));
rect.Y += 266;
e.Graphics.DrawString($"====== END OF FISCAL INVOICE ==========", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
rect.Y += 20;
e.Graphics.DrawString($"Subtotal ({list1.Count()} items)", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString($"{list1.Sum(o => o.amount).ToString("C2").Substring(1)}", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
if (orderTableEntity.payMethodName.Contains("->("))
{
rect.Y += 20;
e.Graphics.DrawString($"===========Aggregated payment============", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
rect.Y += 20;
e.Graphics.DrawString($"Payment method:", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString($"{orderTableEntity.payMethodName}", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
rect.Y += 20;
e.Graphics.DrawString($"Payment Amount:", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString($"{orderTableEntity.payAmount.ToString("C2").Substring(1)}", txtFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
}
if (p.is_cash.ToUpper().Equals("Y") && (list2.Any(o => o.exchangeAmount > 0)))
{
rect.Y += 20;
e.Graphics.DrawString($"Collection:", tipsFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString($"{(orderTableEntity.payAmount + orderTableEntity.payBackAmount).ToString("C2").Substring(1)}", tipsFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
rect.Y += 20;
e.Graphics.DrawString($"Change:", tipsFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_left);
e.Graphics.DrawString($"{orderTableEntity.payBackAmount.ToString("C2").Substring(1)}", tipsFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width - right_space, 20), sf_right);
}
if (!string.IsNullOrEmpty(merchantStoreEntity.store_advertising_footer))
{
rect.Y += 22;
e.Graphics.DrawString($"{merchantStoreEntity.store_advertising_footer}", tipsFont, Brushes.Black, new Rectangle(0, rect.Y, rect.Width, 20), sf_center);
} }
现有软件的一些截图




今天是个好日子,TaxCore(POS软件)备案指北的更多相关文章
- 盘点销售一体机 打印POS一体的设备。 打印,盘点,销售PDA(手持终端)+移动销售POS软件
一.产品介绍 本产品为一个PDA(手持终端)+移动销售POS管理软件组合.可以实现功能如下: 可以实现移动销售(销售退货).盘点.配送.移库.打印小票的功能. 销售时,可以选择客户.业务员.库房,并且 ...
- 有了门面,程序会更加体面!- pos软件基于三层架构 -09
续上篇) 大鸟说道:“实际上没有学过设计模式去理解三层架构会有失偏颇的,毕竟分层是更高一级别的模式,所谓的架构模式.不过在程序中,有意识的遵循设计原则,却也可以有效的做出好的设计.” ...
- 浩瀚科技PDA移动开单|盘点机 数据采集器 条码扫描开单微POS软件 现场打印开单
PDA移动开单,是我公司的一款便携式开单配套产品,PDA能通过蓝牙.无线局域网.互联网直接与主机连接,让公司业务人员能随时随地了解公司产品信息并且进行开单.入库.库存.盘点等一系列进销存操作.是现今企 ...
- mac中使用brew安装软件,下载太慢怎么办?
mac中使用brew安装软件,下载太慢怎么办? 本文所说的软件是指较大的软件,如果软件较小,例如软件只有几M,那么使用此方法后,提升会非常小. 了解brew原理: 1: 从网络下载安装包 2: 执行一 ...
- Linux下软件的安装与管理
1.源码安装方式 2.RPM包方式安装 3.yum安装方式 4.二进制软件安装方式 1.源码安装方式 (1)下载.解压Apache源码: mkdir /apache #在根目录下创建一个apache目 ...
- Awesome图标 | 如何在某些编辑软件中使用Font Awesome字体图标
文章目录 Font Awesome 字体图标 在某些编辑软件中使用 Font Awesome 字体图标 Font Awesome 为您提供可缩放矢量图标,它可以被定制大小.颜色.阴影以及任何可以用 C ...
- Linux下软件安装的四种方式
一.源码安装 步骤: 下载,解压源码(常见的源码打包格式:.tar.gz/.tar.bz2); 可以直接下载源码再上传至linux服务器,或者在联网状态下,直接通过wget等命令获取源码安装包;源码解 ...
- CAX软件资产管理
CAX软件其实指的是计算机辅助设计软件统称,即CAD.CAM.CAE.CAPP.CAS.CAT.CAI等各项技术的综合叫法,因为这些技术的缩写基本都是以CA为起始,X则表示所有.也就是说,CAX实际上 ...
- 哲讯分享:sap软件多少钱一套
SAP软件一般指SAP. SAP,为"System Applications and Products"的简称,是德国SAP公司的产品--企业管理解决方案的软件名称.至今世界500 ...
- Web安全学习
项目地址(参考):https://websec.readthedocs.io/zh/latest/basic/history.html 本文只能充当目录简介,具体还要自己深入学习. 序章 Web技术演 ...
随机推荐
- Python——第一章:占位——pass
pass: 常用于代码占位 a = 10 if a > 100: pass 当设计代码时,有些条件或代码还没有想好要如何处理,先用pass做占位,后续可以回来继续写.如果不写pass则会报错,因 ...
- JavaFx之Ikonli图标库大全(十五)
JavaFx之Ikonli图标库大全(十五) Ikonli给java提供了大量的图标库, 官网:https://kordamp.org/ikonli/ Ikonli 提供了可以在 Java 应用程序中 ...
- P4928 [MtOI2018]衣服?身外之物! 题解
题意 gcd 共有 \(n\) 件衣服,编号为 \(A_1,A_2,\cdots A_n\). 每一件衣服分别拥有颜色值和清洗时间,他在每一件衣服穿完以后都会将其送去清洗,而这件衣服当天所拥有的舒适感 ...
- docker: 'buildx' is not a docker command
解决方法 sudo apt install docker-buildx-plugin
- 【福利活动】华为云“上云之路”征文大赛开启,FreeBuds3无线耳机等重磅好礼送不停
各位关注华为云的开发者们,达嘎猴啊~ 今天带给你们一个好消息,大家心心念念的华为云"上云之路"征文大赛已经正式开启啦. 举办本次华为云"上云之路"征文大赛的目的 ...
- 40个问题让你快速掌握Java多线程的精髓
摘要:多线程可以理解为在同一个程序中能够同时运行多个不同的线程来执行不同的任务,这些线程可以同时利用CPU的多个核心运行. 多线程可以理解为在同一个程序中能够同时运行多个不同的线程来执行不同的任务,这 ...
- webpack原理(3):Tapable源码分析及钩子函数作用分析
webpack本质上是一种事件流的机制,它的工作流程就是将各个插件串联起来,而实现这一切的核心就是Tapable,webpack中最核心的负责编译的Compiler和负责创建bundles的Compi ...
- 开心档之MySQL 导入数据
MySQL 导入数据 本章节我们为大家介绍几种简单的 MySQL 导入数据命令. 1.mysql 命令导入 使用 mysql 命令导入语法格式为: mysql -u用户名 -p密码 < 要导入的 ...
- 火山引擎 DataTester:如何用 A/B 测试做产品增长?
技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 随着如今越来越高的获客成本,用户拉新变得不再容易:而且由于获客成本的增高,让用户留存也变得更加重要.同时,一个产品的使 ...
- 强强联合,ByteHouse 携手亚马逊云科技,新一代云数仓服务重磅升级
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 随着全球化的发展,越来越多的中国企业开始涉足海外市场,开展跨境业务.在这个过程中,强大的数据分析能力是出海企业不可 ...


