package controllers // 移动端进销存单据接口(采购/销售/库存十类单据共用一套路由)。 // // 与 /backend/erp/document* 的关系:handler 与路由各自独立(接口隔离规范), // 单据校验、明细装配、落库事务、审批提交与生效联动全部复用 erp_document_core.go, // 因此手机端开的一张单和 Web 端开的完全等价——同一行记录、同一套库存流水。 // AppErpDocumentController 单据中心(移动端) type AppErpDocumentController struct { AppErpBaseController } // List GET /api/erp/document/list func (c *AppErpDocumentController) List() { cl, err := c.erpClaims() if c.erpDenied(err) { return } page, pageSize := c.erpPage() f := erpDocFilter{ DocType: c.erpQuery("doc_type"), DocTypes: c.erpQuery("doc_types"), Status: c.erpQuery("status"), Keyword: c.erpQuery("keyword"), PartnerID: c.erpUint("partner_id"), WarehouseID: c.erpUint("warehouse_id"), SourceDocID: c.erpUint("source_doc_id"), DateFrom: c.erpQuery("date_from"), DateTo: c.erpQuery("date_to"), } list, total, code, msg := erpDocListCore(c.actor(cl), f, page, pageSize) if msg != "" { c.erpFail(code, code, msg) return } c.erpListOK(list, total, page, pageSize, nil) } // Detail GET /api/erp/document/detail/:id func (c *AppErpDocumentController) Detail() { cl, err := c.erpClaims() if c.erpDenied(err) { return } id := c.erpPathID() doc, code, msg := erpDocDetailCore(c.actor(cl), id) if msg != "" { c.erpFail(code, code, msg) return } c.erpOk(doc) } // Save POST /api/erp/document/save 新建或覆盖保存草稿(body 带 id 即为编辑) func (c *AppErpDocumentController) Save() { cl, err := c.erpClaims() if c.erpDenied(err) { return } var p erpDocPayload if !c.erpBody(&p, false) { return } id, docNo, code, msg := erpDocSaveCore(c.actor(cl), p) if msg != "" { c.erpFail(code, code, msg) return } c.erpOk(map[string]interface{}{"id": id, "doc_no": docNo}) } // Delete DELETE /api/erp/document/delete/:id 仅草稿/驳回可删除(软删) func (c *AppErpDocumentController) Delete() { cl, err := c.erpClaims() if c.erpDenied(err) { return } id := c.erpPathID() code, msg := erpDocDeleteCore(c.actor(cl), id) if msg != "" { c.erpFail(code, code, msg) return } c.erpOk(nil) } // Cancel POST /api/erp/document/cancel/:id 作废单据 func (c *AppErpDocumentController) Cancel() { cl, err := c.erpClaims() if c.erpDenied(err) { return } id := c.erpPathID() code, msg := erpDocCancelCore(c.actor(cl), id) if msg != "" { c.erpFail(code, code, msg) return } c.erpOk(nil) } // Approve POST /api/erp/document/approve/:id 直接审核生效(未走审批流时使用) func (c *AppErpDocumentController) Approve() { cl, err := c.erpClaims() if c.erpDenied(err) { return } id := c.erpPathID() code, msg := erpDocApproveCore(c.actor(cl), id) if msg != "" { c.erpFail(code, code, msg) return } c.erpOk(nil) } // Submit POST /api/erp/document/submit/:id?flow_id= 提交审批流 func (c *AppErpDocumentController) Submit() { cl, err := c.erpClaims() if c.erpDenied(err) { return } id := c.erpPathID() instID, code, msg := erpDocSubmitCore(c.actor(cl), id, c.erpUint("flow_id")) if msg != "" { c.erpFail(code, code, msg) return } c.erpOk(map[string]interface{}{"instance_id": instID}) } // Flows GET /api/erp/document/flows?doc_type= 该单据类型可用的审批流 func (c *AppErpDocumentController) Flows() { cl, err := c.erpClaims() if c.erpDenied(err) { return } bizType, flows, code, msg := erpDocFlowsCore(c.actor(cl), c.erpQuery("doc_type")) if msg != "" { c.erpFail(code, code, msg) return } c.erpOk(map[string]interface{}{"list": flows, "biz_type": bizType}) } // Executable GET /api/erp/document/executable/:id 来源订单中尚可执行的明细行 func (c *AppErpDocumentController) Executable() { cl, err := c.erpClaims() if c.erpDenied(err) { return } id := c.erpPathID() data, code, msg := erpDocExecutableCore(c.actor(cl), id) if msg != "" { c.erpFail(code, code, msg) return } c.erpOk(data) } // TakeSheet GET /api/erp/document/takeSheet?warehouse_id= 盘点表初始化 func (c *AppErpDocumentController) TakeSheet() { cl, err := c.erpClaims() if c.erpDenied(err) { return } list, code, msg := erpTakeSheetCore(c.actor(cl), c.erpUint("warehouse_id")) if msg != "" { c.erpFail(code, code, msg) return } c.erpOk(map[string]interface{}{"list": list}) } // Meta GET /api/erp/document/meta 开单页字典(单据类型/状态/默认仓库/价格口径) func (c *AppErpDocumentController) Meta() { cl, err := c.erpClaims() if c.erpDenied(err) { return } c.erpOk(erpDocMetaDict(c.actor(cl))) }