• 今天是个好日子,TaxCore(POS软件)备案指北


    POS软件是什么?你好意思吗,还在用老掉牙的Winform。

     

    关于POS

    销售终端——POS(point of sale)是一种多功能终端,把它安装在信用卡的特约商户和受理网点中与计算机联成网络,就能实现电子资金自动转账,它具有支持消费、预授权、余额查询和转账等功能,使用起来安全、快捷、可靠。

     POS软件大都长这样子:

    不好意思了,我没有专门去收集POS软件的UI界面。感兴趣的朋友可以去澳大利亚知名POS软件供应商IDEALPOS的官网去围观:

    POS Systems Australia - Software & Hardware - Idealpos 

     

     

    前言

     好久以前就想写这篇文章了,一是想要证明我还在程序员队伍里苟延残喘。二是这样的文章我从来就没看见过,写出来万一帮到其他人了呢。今天早上我查看请求的状态时豁然发现已经通过平台的审核了,接下来就是区域的审核:我们公司在Fiji和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 POStitle>
        <meta charset="utf-8">
    head>
    <body>
        <h1>Online POSh1>
        <label for="invoiceRequest">Invoice request jsonlabel>
        <textarea id="invoiceRequest" cols="100" rows="30" style="display:block">textarea>
        <label for="taxcore_sign_element">Send Invoice Request:label>
        
        <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 Invoicebutton>
        <label for="results">Received Signed Invoice:label>    
        <textarea readonly id="results" cols="100" rows="30">textarea>
        
        <script src=" https://vsdc.sandbox.taxcore.online/onlinepos/v1/taxcore.min.js">script>    
        
        <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发起发票请求的代码:

    复制代码
     /// 
     /// 发起联网发票请求
     /// 
     /// 订单
     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();
         var s2 = new BaseRepository();
         var s3 = new BaseRepository();
         var list1 = s1.GetList(p => p.order_No == bill.orderNo);
         var list2 = s2.GetList(p => p.order_No == bill.orderNo);
         List items = new List();
         var goodsSvr = new BaseRepository();
         #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();
             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(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}]");
         }
     }
    
    
    
     /// 
     /// 请求地址赋值
     /// 
     /// 
     /// 
     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();
     }
     /// 
     /// 请求加入证书
     /// 
     /// 
     private WebRequestHandler CreateWebRequestHandler()
     {
         var handler = new WebRequestHandler();
         var cert = GetClientCertificate();
         handler.ClientCertificateOptions = ClientCertificateOption.Manual;
         handler.ClientCertificates.Add(cert);
         return handler;
     }
     /// 
     /// 读取证书
     /// 
     /// 
     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;
     }
    复制代码

    关于打印的代码就有点冗长了,请无视我的复制和粘帖运用得如此炉火纯青。

    复制代码
    /// 
    /// 发票绘制
    /// 
    /// 
    /// 
    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();
        var s2 = new BaseRepository();
        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();
        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();
        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);
        }
        
    }
    复制代码

     

    现有软件的一些截图

     

     

     

     

     本文谢绝转载!!!

  • 相关阅读:
    03 nginx 是如何自动推导文件的 content-type 的
    【C#】Mapster对象映射的使用
    go 线程限制数量 --chatGPT
    每日一题 —— LC. 792 匹配子序列的单词数
    Asp.Net Core&Jaeger实现链路追踪
    8051(c51)单片机从汇编到C语言,从Boot到应用实践教程
    Flutter: 发送 http 请求
    阿里一面 | 说说你对 MySQL 死锁的理解
    Linux安装Whisper-Jax
    又拿三个大奖?!多力就是要让你吃的更营养更健康
  • 原文地址:https://www.cnblogs.com/datacool/p/17984042/TaxCore2024