Files
17168ERP/web/App_Code/api/receiptController.cs
T
2026-07-27 06:28:06 +08:00

486 lines
21 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Drawing;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Vml;
using DocumentFormat.OpenXml.Wordprocessing;
using Model;
using NPOI.OpenXmlFormats.Wordprocessing;
using NPOI.Util;
using PagedList;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web;
using System.Web.Http;
using System.Web.UI.WebControls;
using Break = DocumentFormat.OpenXml.Wordprocessing.Break;
using Paragraph = DocumentFormat.OpenXml.Wordprocessing.Paragraph;
using Run = DocumentFormat.OpenXml.Wordprocessing.Run;
using Table = DocumentFormat.OpenXml.Wordprocessing.Table;
using Text = DocumentFormat.OpenXml.Wordprocessing.Text;
/// <summary>
/// receiptController 的摘要描述
/// </summary>
[ezAuthorize]
public class receiptController: ApiController
{
private Model.ezEntities _db = new Model.ezEntities();
public receiptController()
{
//
// TODO: 在這裡新增建構函式邏輯
//
}
public string generend_receiptNo(string source,string receipt_date)
{
string start ="1"+ (source=="1"?"A":"B");
string no = start + receipt_date; //DateTime.Now.ToString("yyyyMMdd");
var qry = _db.receipt_detail.Where(x => x.receipt_no.StartsWith(no));
var receipt_no=qry.Select(x => x.receipt_no).Max();
if (!string.IsNullOrEmpty(receipt_no))
{
receipt_no= receipt_no.Remove(0,(start + receipt_date.Replace("-","")).Length);
return start + receipt_date.Replace("-", "") + string.Format("{0:D4}", Int32.Parse(receipt_no)+1);
}
else
{
return start + receipt_date.Replace("-", "") + "0001";
}
}
[HttpPost]
[Route("api/receipt/UpdateReceiptWithDetail")]
public IHttpActionResult UpdateReceiptWithDetail([FromBody] Model.ViewModel.receipt_master receipt)
{
int master_no = 0;
try
{
//Model.receipt_master m = new Model.receipt_master();
List<Model.receipt_detail> list = new List<Model.receipt_detail>();
var master = _db.receipt_master.Where(x => x.num == receipt.num).FirstOrDefault();
if (master != null)
{
master.u_time = DateTime.Now.ToString("HHmmss");
master.u_date = DateTime.Now.ToString("yyyyMMdd");
}
master_no=master.num;
//m.receipt_date = receipt.receipt_date;
//m.order_no = receipt.order_no;
//m.total_amt = receipt.total_amt;
//m.style_num = receipt.style_num;
//m.source = receipt.source;
//m.num=(int)receipt.num;
//m.c_date = DateTime.Now.ToString("yyyyMMdd");
//m.c_time = DateTime.Now.ToString("HHmmss");
//m.u_time = DateTime.Now.ToString("HHmmss");
//m.u_date = DateTime.Now.ToString("yyyyMMdd");
//_db.receipt_master.Add(m);
//_db.SaveChanges();
//master_no = m.num;
string pre_no = string.Empty;
foreach (var d in receipt.list)
{
if (d.num == 0)
{
receipt_detail dd = new receipt_detail();
if (string.IsNullOrEmpty(pre_no))
{
dd.receipt_no = generend_receiptNo(master.source,d.receipt_date.Replace("-",""));
}
else
{
string new_no = pre_no.Remove(0, 10);
dd.receipt_no = "1"+(master.source=="1"?"A":"B" )+d.receipt_date.Replace("-","") + string.Format("{0:D4}", Int32.Parse(new_no) + 1);
}
dd.addr = d.addr;
dd.title = d.title;
dd.amt = d.amt;
dd.caseofficer = d.caseofficer;
dd.receipt_date= d.receipt_date;
dd.receipt_item = d.receipt_item;
dd.receipt_num = master.num;
dd.c_date = DateTime.Now.ToString("yyyyMMdd");
dd.c_time = DateTime.Now.ToString("HHmmss");
dd.u_time = DateTime.Now.ToString("HHmmss");
dd.u_date = DateTime.Now.ToString("yyyyMMdd");
pre_no = dd.receipt_no;
list.Add(dd);
}
else
{
var dd=_db.receipt_detail.Where(x=>x.num==d.num).FirstOrDefault();
dd.title=d.title;
dd.amt=d.amt;
dd.caseofficer=d.caseofficer;
dd.receipt_item=d.receipt_item;
dd.u_time = DateTime.Now.ToString("HHmmss");
dd.u_date = DateTime.Now.ToString("yyyyMMdd");
}
}
_db.receipt_detail.AddRange(list);
_db.SaveChanges();
return Ok(new { result = "Y", message = "存檔成功" });
}
catch (Exception ex)
{
var s = _db.receipt_master.Where(x => x.num == master_no).FirstOrDefault();
if (s != null)
{
_db.receipt_master.Remove(s);
_db.SaveChanges();
}
return Ok(new { result = "N", message = $"存檔失敗,{ex.Message} {ex.StackTrace}" });
}
}
[HttpPost]
[Route("api/receipt/SaveReceiptWithDetail")]
public IHttpActionResult SaveReceiptWithDetail([FromBody] Model.ViewModel.receipt_master receipt)
{
int master_no = 0;
try
{
Model.receipt_master m = new Model.receipt_master();
List<Model.receipt_detail> list = new List<Model.receipt_detail>();
m.receipt_date = receipt.receipt_date;
m.order_no = receipt.order_no;
m.total_amt = receipt.total_amt;
m.style_num = receipt.style_num;
m.source = receipt.source;
m.c_date = DateTime.Now.ToString("yyyyMMdd");
m.c_time = DateTime.Now.ToString("HHmmss");
m.u_time= DateTime.Now.ToString("HHmmss");
m.u_date = DateTime.Now.ToString("yyyyMMdd");
_db.receipt_master.Add(m);
_db.SaveChanges();
master_no = m.num;
string pre_no = string.Empty;
foreach (var d in receipt.list)
{
receipt_detail dd = new receipt_detail();
if (string.IsNullOrEmpty(pre_no))
{
dd.receipt_no = generend_receiptNo(m.source, d.receipt_date.Replace("-", ""));
}
else
{
string new_no = pre_no.Remove(0,10);
dd.receipt_no ="1"+ (m.source=="1"?"A":"B") + d.receipt_date.Replace("-", "") + string.Format("{0:D4}", Int32.Parse(new_no)+1);
}
dd.addr = d.addr;
dd.title = d.title;
dd.amt = d.amt;
dd.caseofficer = d.caseofficer;
dd.receipt_date=d.receipt_date;
dd.receipt_item = d.receipt_item;
dd.receipt_num = m.num;
dd.c_date = DateTime.Now.ToString("yyyyMMdd");
dd.c_time = DateTime.Now.ToString("HHmmss");
dd.u_time = DateTime.Now.ToString("HHmmss");
dd.u_date = DateTime.Now.ToString("yyyyMMdd");
pre_no = dd.receipt_no;
list.Add(dd);
}
_db.receipt_detail.AddRange(list);
_db.SaveChanges();
return Ok(new {result="Y",message="存檔成功"});
}
catch (Exception ex)
{
var s=_db.receipt_master.Where(x=>x.num==master_no).FirstOrDefault();
if (s != null)
{
_db.receipt_master.Remove(s);
_db.SaveChanges();
}
return Ok(new { result = "N", message = $"存檔失敗,{ex.Message} {ex.StackTrace}" });
}
}
[HttpPost]
[Route("api/receipt/GetList")]
public IHttpActionResult GetList([FromBody] Model.ViewModel.receipt_master r,
int page, int pageSize = 10, string sortBy = "", bool sortDesc = false)
{
var qry = _db.receipt_master.AsQueryable();
if (r.num.HasValue)
qry = qry.Where(x => x.num == r.num.Value);
if (!string.IsNullOrEmpty(r.receipt_date))
qry = qry.Where(x=>x.receipt_date==r.receipt_date);
if (!string.IsNullOrEmpty(r.source))
qry = qry.Where(x => x.source == r.source);
if (!string.IsNullOrEmpty(r.order_no))
qry = qry.Where(x => x.order_no == r.order_no);
qry=qry.OrderBy(x => x.num);
var count = qry.Count();
var qryList = (pageSize > 0) ? qry.ToPagedList(page, pageSize).ToList() : qry.ToList();
var ret = new
{
list = qryList.Select(x => new
{
x.num,x.source,x.order_no,x.total_amt,x.receipt_date,x.style_num,
follower=_db.pro_order.Where(y=>y.order_no==x.order_no).Select(y=>new {
u_name=_db.followers.Where(z=>z.num==y.f_num).Select(z=>z.u_name).FirstOrDefault(),
}).FirstOrDefault(),
receipt_count=_db.receipt_detail.Where(w=>w.receipt_num==x.num).Count()
}),
count=count
};
if (ret.list == null) throw new HttpResponseException(HttpStatusCode.NotFound);
return Ok(ret);
}
[HttpPost]
[Route("api/receipt/GetData")]
public IHttpActionResult GetData([FromBody] Model.ViewModel.receipt_master r)
{
var qry = _db.receipt_master.AsQueryable();
if (r.num.HasValue)
qry = qry.Where(x => x.num == r.num.Value);
if (!string.IsNullOrEmpty(r.receipt_date))
qry = qry.Where(x => x.receipt_date == r.receipt_date);
if (!string.IsNullOrEmpty(r.source))
qry = qry.Where(x => x.source == r.source);
if (!string.IsNullOrEmpty(r.order_no))
qry = qry.Where(x => x.order_no == r.order_no);
qry = qry.OrderBy(x => x.num);
var ret = new
{
data = qry.Select(x => new
{
x.num,
x.source,
x.order_no,
x.total_amt,
x.receipt_date,
x.style_num,
follower = _db.pro_order.Where(y => y.order_no == x.order_no).Select(y => new {
u_name = _db.followers.Where(z => z.num == y.f_num).Select(z => z.u_name).FirstOrDefault(),
}).FirstOrDefault(),
receipt_detail = _db.receipt_detail.Where(w => w.receipt_num == x.num).ToList(),
orderdetails=_db.pro_order_detail.Where(q=>q.order_no==x.order_no).Select(q=>new
{
records=_db.pro_order_record.Where(rc=>rc.detail_num==q.num).Select(rc=>rc.price).ToList(),
}).ToList()
}).FirstOrDefault(),
};
if (ret.data == null) throw new HttpResponseException(HttpStatusCode.NotFound);
return Ok(ret);
}
[HttpPost]
[Route("api/receipt/GetAllStyle")]
public IHttpActionResult GetAllStyle()
{
var qry = _db.receipt_style.AsQueryable();
return Ok(new { result = "Y", list = qry.ToList() });
}
[HttpPost]
[Route("api/receipt/PrintReceipt")]
public HttpResponseMessage PrintReceipt([FromBody] Model.receipt_master r)
{
var qry=_db.receipt_master.AsQueryable();
qry = qry.Where(x=>x.num==r.num);
var data = qry.Select(x=>new
{
x.num,x.receipt_date,x.source,x.order_no,x.style_num,
details=_db.receipt_detail.Where(y=>y.receipt_num==x.num).ToList(),
styleDetail=_db.receipt_style_d.Where(z=>z.style_num==x.style_num).ToList(),
}).FirstOrDefault();
try
{
string templatePath = HttpContext.Current.Server.MapPath("~/rpt/sample/receipt_sample01.docx");
if (!File.Exists(templatePath))
{
return Request.CreateResponse(HttpStatusCode.NotFound, "Template file not found.");
}
byte[] templateBytes = File.ReadAllBytes(templatePath);
// 2. 建立記憶體串流
MemoryStream outputStream = new MemoryStream();
outputStream.Write(templateBytes, 0, templateBytes.Length);
// 3. 使用 Open XML 處理記憶體中的資料
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(outputStream, true))
{
var body = wordDoc.MainDocumentPart.Document.Body;
var templateTable = body.Elements<Table>().FirstOrDefault();
if (templateTable != null && data.details != null && data.details.Count > 0)
{
OpenXmlElement currentAnchor = templateTable;
// 建立全域計數器 (請實作於迴圈外部,避免歸零)
int docPrIdCounter = 1000;
int vmlIdCounter = 2000;
for (int i = 0; i < data.details.Count; i++)
{
Table newTable = (Table)templateTable.CloneNode(true);
// --- 步驟 A:修復 DrawingML 的 docPr ID ---
foreach (var docPr in newTable.Descendants<DocumentFormat.OpenXml.Drawing.Wordprocessing.DocProperties>())
{
docPr.Id = (uint)docPrIdCounter++;
// 順便變更 Name,避免如 "直線接點 2" 的名稱重複
docPr.Name = $"直線接點_{docPrIdCounter}";
}
// --- 步驟 B:修復 VML 的 id 與 o:spid ---
foreach (var line in newTable.Descendants<Line>())
{
string newSpid = $"_x0000_s{vmlIdCounter++}";
// 更新原本的 v:line id
line.Id = $"直線接點_{vmlIdCounter}";
// o:spid 屬於 Office 擴充屬性,透過 SetAttribute 強制覆寫
var oNamespace = "urn:schemas-microsoft-com:office:office";
line.SetAttribute(new OpenXmlAttribute("spid", "o", oNamespace, newSpid));
}
// 移除複製出來的書籤標籤,保持結構乾淨
var bookmarksStarts = newTable.Descendants<BookmarkStart>().ToList();
var bookmarksEnds = newTable.Descendants<BookmarkEnd>().ToList();
foreach (var bm in bookmarksStarts) bm.Remove();
foreach (var bm in bookmarksEnds) bm.Remove();
foreach (var p in newTable.Descendants<Paragraph>())
{
p.RsidParagraphAddition = null;
p.RsidParagraphDeletion = null;
p.RsidParagraphProperties = null;
p.RsidRunAdditionDefault = null;
}
var textElements = newTable.Descendants<Text>().ToList();
foreach (var textNode in textElements)
{
// 檢查文字節點是否包含指定的關鍵字,並進行置換
if (textNode.Text.Contains("$CompanyTitle"))
{
var companyTitle = data.styleDetail.Where(x => x.item_name == "CompanyTitle").Select(x => x.item_value).FirstOrDefault();
textNode.Text = textNode.Text.Replace("$CompanyTitle", companyTitle ?? "");
}
if (textNode.Text.Contains("$ApproveNo"))
{
var approveNo = data.styleDetail.Where(x => x.item_name == "ApproveNo").Select(x => x.item_value).FirstOrDefault();
textNode.Text = textNode.Text.Replace("$ApproveNo", approveNo ?? "");
}
if (textNode.Text.Contains("$CompanyTaxNo"))
{
var companyTaxNo = data.styleDetail.Where(x => x.item_name == "CompanyTaxNo").Select(x => x.item_value).FirstOrDefault();
textNode.Text = textNode.Text.Replace("$CompanyTaxNo", companyTaxNo ?? "");
}
if (textNode.Text.Contains("$CompanyAddr"))
{
var companyAddr = data.styleDetail.Where(x => x.item_name == "CompanyAddr").Select(x => x.item_value).FirstOrDefault();
textNode.Text = textNode.Text.Replace("$CompanyAddr", companyAddr ?? "");
}
if (textNode.Text.Contains("$CompanyTel"))
{
var companyTel = data.styleDetail.Where(x => x.item_name == "CompanyTel").Select(x => x.item_value).FirstOrDefault();
textNode.Text = textNode.Text.Replace("$CompanyTel", companyTel ?? "");
}
if (textNode.Text.Contains("$ReceiptNo"))
{
textNode.Text = textNode.Text.Replace("$ReceiptNo", data.details[i].receipt_no ?? "");
}
if (textNode.Text.Contains("$ReceiptDate"))
{
textNode.Text = textNode.Text.Replace("$ReceiptDate", data.receipt_date ?? "");
}
if (textNode.Text.Contains("$ReceiptTitle"))
{
textNode.Text = textNode.Text.Replace("$ReceiptTitle", data.details[i].title ?? "");
}
if (textNode.Text.Contains("$ReceiptAmt"))
{
textNode.Text = textNode.Text.Replace("$ReceiptAmt", data.details[i].amt.ToString() ?? "");
}
if (textNode.Text.Contains("$Charge"))
{
textNode.Text = textNode.Text.Replace("$Charge", "" ?? "");
}
if (textNode.Text.Contains("$Caseofficer"))
{
textNode.Text = textNode.Text.Replace("$Caseofficer", data.details[i].caseofficer ?? "");
}
}
currentAnchor= body.InsertAfter(newTable, currentAnchor);
//currentAnchor = newTable;
if (i < data.details.Count - 1)
{
Paragraph pageBreakParagraph = new Paragraph(
new Run(
new Break() { Type = BreakValues.Page }
)
);
// 🔥【關鍵修正】將分頁段落插入到剛才產生的新表格後方
currentAnchor = body.InsertAfter(pageBreakParagraph, currentAnchor);
}
}
body.RemoveChild(templateTable);
wordDoc.MainDocumentPart.Document.Save();
}
} // wordDoc 關閉,確認資料完全寫入 outputStream
// 🔥 關鍵步驟:重設記憶體串流指標到起點
outputStream.Position = 0;
// 4. 建立 HttpResponseMessage
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
// 將記憶體流包裝成 StreamContent
response.Content = new StreamContent(outputStream);
// 設定 Content-Type 標頭(Word 專用 MIME Type
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
// 設定 Content-Disposition 標頭,指定為附件並提供預設檔名
string fileName = $"Report_{DateTime.Now:yyyyMMddHHmmss}.docx";
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = fileName
};
return response;
}
catch (Exception ex)
{
// Log exception details appropriately here
return Request.CreateResponse(HttpStatusCode.InternalServerError, $"Generation failed: {ex.Message}");
}
}
}