530 lines
17 KiB
Go
530 lines
17 KiB
Go
package controllers
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
"server/models"
|
|
erp "server/services/erp"
|
|
|
|
"github.com/beego/beego/v2/client/orm"
|
|
)
|
|
|
|
// ERP 往来账/收付款核心(两端共用):/backend/erp/finance* 与 /api/erp/finance* 都调这里,
|
|
// 未收未付、账龄、核销余额等口径只算一次,手机端不会看到与 Web 端不一致的应收应付。
|
|
|
|
// erpBillFilter 往来账查询条件
|
|
type erpBillFilter struct {
|
|
BillType string
|
|
PartnerID uint64
|
|
PartnerType string
|
|
SourceDocID uint64
|
|
SettleState string // open|part|done
|
|
Keyword string
|
|
DateFrom string
|
|
DateTo string
|
|
}
|
|
|
|
// erpBillListCore 往来账列表 + 未结余额合计
|
|
func erpBillListCore(a erpActor, f erpBillFilter, page, pageSize int) ([]map[string]interface{}, int64, map[string]float64, int, string) {
|
|
qs := models.Orm.QueryTable(new(models.ErpPartnerBill)).Filter("tenant_id", a.Tid)
|
|
if f.BillType != "" {
|
|
qs = qs.Filter("bill_type", f.BillType)
|
|
}
|
|
if f.PartnerID > 0 {
|
|
qs = qs.Filter("partner_id", f.PartnerID)
|
|
}
|
|
if f.PartnerType != "" {
|
|
qs = qs.Filter("partner_type", f.PartnerType)
|
|
}
|
|
if f.SourceDocID > 0 {
|
|
qs = qs.Filter("source_doc_id", f.SourceDocID)
|
|
}
|
|
switch f.SettleState {
|
|
case "open":
|
|
qs = qs.Filter("status__lt", 2)
|
|
case "part":
|
|
qs = qs.Filter("status", 1)
|
|
case "done":
|
|
qs = qs.Filter("status", 2)
|
|
}
|
|
if f.Keyword != "" {
|
|
cond := orm.NewCondition().
|
|
Or("partner_name__contains", f.Keyword).
|
|
Or("source_doc_no__contains", f.Keyword)
|
|
qs = qs.SetCond(qs.GetCond().AndCond(cond))
|
|
}
|
|
for _, d := range []struct {
|
|
raw string
|
|
cond string
|
|
}{{f.DateFrom, "bill_date__gte"}, {f.DateTo, "bill_date__lte"}} {
|
|
if strings.TrimSpace(d.raw) == "" {
|
|
continue
|
|
}
|
|
if t, e := time.ParseInLocation("2006-01-02", strings.TrimSpace(d.raw), time.Local); e == nil {
|
|
qs = qs.Filter(d.cond, t)
|
|
}
|
|
}
|
|
|
|
total, _ := qs.Count()
|
|
var rows []models.ErpPartnerBill
|
|
if _, err := qs.OrderBy("-bill_date", "-id").Limit(pageSize, (page-1)*pageSize).All(&rows); err != nil {
|
|
return nil, 0, nil, 500, "查询失败: " + err.Error()
|
|
}
|
|
// 摘要区合计:未收/未付总额与本页余额
|
|
var openRecv, openPay float64
|
|
var allRows []models.ErpPartnerBill
|
|
_, _ = models.Orm.QueryTable(new(models.ErpPartnerBill)).
|
|
Filter("tenant_id", a.Tid).Filter("status__lt", 2).
|
|
All(&allRows, "bill_type", "amount", "settled_amount")
|
|
for _, b := range allRows {
|
|
bal := b.Amount - b.SettledAmount
|
|
if b.BillType == models.ErpBillReceivable {
|
|
openRecv += bal
|
|
} else {
|
|
openPay += bal
|
|
}
|
|
}
|
|
out := make([]map[string]interface{}, 0, len(rows))
|
|
now := time.Now()
|
|
for _, b := range rows {
|
|
bal := round2f(b.Amount - b.SettledAmount)
|
|
overdue := 0
|
|
if b.DueDate != nil && b.Status < 2 {
|
|
d := int(b.DueDate.Sub(now).Hours() / 24)
|
|
if d < 0 {
|
|
overdue = -d
|
|
}
|
|
}
|
|
out = append(out, map[string]interface{}{
|
|
"bill": b, "balance": bal, "overdue_days": overdue,
|
|
"status_label": erpBillStatusLabel(b.Status),
|
|
})
|
|
}
|
|
return out, total, map[string]float64{
|
|
"open_receivable": round2f(openRecv), "open_payable": round2f(openPay),
|
|
}, 200, ""
|
|
}
|
|
|
|
// erpBillDetailCore 往来账详情(含核销记录与原单据)
|
|
func erpBillDetailCore(a erpActor, id uint64) (map[string]interface{}, int, string) {
|
|
if id == 0 {
|
|
return nil, 400, "无效的ID"
|
|
}
|
|
var bill models.ErpPartnerBill
|
|
if err := models.Orm.QueryTable(new(models.ErpPartnerBill)).
|
|
Filter("id", id).Filter("tenant_id", a.Tid).One(&bill); err != nil {
|
|
return nil, 404, "往来账未找到"
|
|
}
|
|
var settles []models.ErpFundSettle
|
|
_, _ = models.Orm.QueryTable(new(models.ErpFundSettle)).
|
|
Filter("tenant_id", a.Tid).Filter("partner_bill_id", id).OrderBy("-id").All(&settles)
|
|
fundIDs := make([]uint64, 0, len(settles))
|
|
for _, s := range settles {
|
|
fundIDs = append(fundIDs, s.FundBillID)
|
|
}
|
|
fundMap := map[uint64]models.ErpFundBill{}
|
|
if len(fundIDs) > 0 {
|
|
var funds []models.ErpFundBill
|
|
_, _ = models.Orm.QueryTable(new(models.ErpFundBill)).
|
|
Filter("id__in", fundIDs).All(&funds, "id", "fund_no", "fund_type", "biz_date", "pay_method")
|
|
for _, fn := range funds {
|
|
fundMap[fn.ID] = fn
|
|
}
|
|
}
|
|
items := erpDocItems(models.Orm, bill.SourceDocID)
|
|
return map[string]interface{}{
|
|
"bill": bill,
|
|
"balance": round2f(bill.Amount - bill.SettledAmount),
|
|
"settles": settles,
|
|
"funds": fundMap,
|
|
"doc_items": items,
|
|
}, 200, ""
|
|
}
|
|
|
|
// erpPartnerAging 单个往来单位的账龄分布
|
|
type erpPartnerAging struct {
|
|
PartnerID uint64 `json:"partner_id"`
|
|
PartnerName string `json:"partner_name"`
|
|
BillType int8 `json:"bill_type"`
|
|
Total float64 `json:"total"`
|
|
Buckets map[string]float64 `json:"buckets"`
|
|
}
|
|
|
|
// erpAgingCore 账龄分析(按未结余额分桶)
|
|
func erpAgingCore(a erpActor) (map[string]interface{}, int, string) {
|
|
buckets := []struct {
|
|
Label string `json:"label"`
|
|
Min int `json:"min"`
|
|
Max int `json:"max"`
|
|
}{
|
|
{"未到期", -99999, 0}, {"1-30天", 1, 30}, {"31-60天", 31, 60},
|
|
{"61-90天", 61, 90}, {"90天以上", 91, 99999},
|
|
}
|
|
agg := map[string]*erpPartnerAging{}
|
|
var bills []models.ErpPartnerBill
|
|
_, _ = models.Orm.QueryTable(new(models.ErpPartnerBill)).
|
|
Filter("tenant_id", a.Tid).Filter("status__lt", 2).
|
|
All(&bills, "partner_id", "partner_name", "bill_type", "amount", "settled_amount", "due_date", "bill_date")
|
|
now := time.Now()
|
|
sum := map[string]map[string]float64{}
|
|
for _, b := range bills {
|
|
// 分组必须带上 bill_type:同一客商既挂应收又挂应付时,只按 partner 归并
|
|
// 会把两种账期混进行里,导致 list 合计与 summary(按单据类型分)对不上。
|
|
key := b.PartnerType + ":" + fmt.Sprintf("%d:%d", b.PartnerID, b.BillType)
|
|
pa := agg[key]
|
|
if pa == nil {
|
|
pa = &erpPartnerAging{
|
|
PartnerID: b.PartnerID, PartnerName: b.PartnerName, BillType: b.BillType,
|
|
Buckets: map[string]float64{},
|
|
}
|
|
agg[key] = pa
|
|
}
|
|
ref := b.DueDate
|
|
if ref == nil {
|
|
ref = &b.BillDate
|
|
}
|
|
days := int(now.Sub(*ref).Hours() / 24)
|
|
label := buckets[0].Label
|
|
for _, bk := range buckets {
|
|
if days >= bk.Min && days <= bk.Max {
|
|
label = bk.Label
|
|
break
|
|
}
|
|
}
|
|
bal := round2f(b.Amount - b.SettledAmount)
|
|
pa.Total = round2f(pa.Total + bal)
|
|
pa.Buckets[label] = round2f(pa.Buckets[label] + bal)
|
|
bt := "receivable"
|
|
if b.BillType == models.ErpBillPayable {
|
|
bt = "payable"
|
|
}
|
|
if sum[bt] == nil {
|
|
sum[bt] = map[string]float64{}
|
|
}
|
|
sum[bt][label] = round2f(sum[bt][label] + bal)
|
|
}
|
|
list := make([]*erpPartnerAging, 0, len(agg))
|
|
for _, pa := range agg {
|
|
list = append(list, pa)
|
|
}
|
|
return map[string]interface{}{"list": list, "summary": sum, "buckets": buckets}, 200, ""
|
|
}
|
|
|
|
// erpFundFilter 收付款单查询条件
|
|
type erpFundFilter struct {
|
|
FundType string
|
|
Status string
|
|
PartnerID uint64
|
|
Keyword string
|
|
DateFrom string
|
|
DateTo string
|
|
}
|
|
|
|
// erpFundListCore 收付款单列表
|
|
func erpFundListCore(a erpActor, f erpFundFilter, page, pageSize int) ([]models.ErpFundBill, int64, int, string) {
|
|
qs := models.Orm.QueryTable(new(models.ErpFundBill)).
|
|
Filter("tenant_id", a.Tid).Filter("delete_time__isnull", true)
|
|
if f.FundType != "" {
|
|
qs = qs.Filter("fund_type", f.FundType)
|
|
}
|
|
if f.Status != "" {
|
|
qs = qs.Filter("status", f.Status)
|
|
}
|
|
if f.PartnerID > 0 {
|
|
qs = qs.Filter("partner_id", f.PartnerID)
|
|
}
|
|
if f.Keyword != "" {
|
|
cond := orm.NewCondition().
|
|
Or("fund_no__contains", f.Keyword).
|
|
Or("partner_name__contains", f.Keyword)
|
|
qs = qs.SetCond(qs.GetCond().AndCond(cond))
|
|
}
|
|
for _, d := range []struct {
|
|
raw string
|
|
cond string
|
|
}{{f.DateFrom, "biz_date__gte"}, {f.DateTo, "biz_date__lte"}} {
|
|
if strings.TrimSpace(d.raw) == "" {
|
|
continue
|
|
}
|
|
if t, e := time.ParseInLocation("2006-01-02", strings.TrimSpace(d.raw), time.Local); e == nil {
|
|
qs = qs.Filter(d.cond, t)
|
|
}
|
|
}
|
|
total, _ := qs.Count()
|
|
var rows []models.ErpFundBill
|
|
if _, err := qs.OrderBy("-id").Limit(pageSize, (page-1)*pageSize).All(&rows); err != nil {
|
|
return nil, 0, 500, "查询失败: " + err.Error()
|
|
}
|
|
return rows, total, 200, ""
|
|
}
|
|
|
|
// erpFundDetailCore 收付款单详情(含核销明细与对应往来账)
|
|
func erpFundDetailCore(a erpActor, id uint64) (map[string]interface{}, int, string) {
|
|
if id == 0 {
|
|
return nil, 400, "无效的ID"
|
|
}
|
|
var fund models.ErpFundBill
|
|
if err := models.Orm.QueryTable(new(models.ErpFundBill)).
|
|
Filter("id", id).Filter("tenant_id", a.Tid).
|
|
Filter("delete_time__isnull", true).One(&fund); err != nil {
|
|
return nil, 404, "收付款单未找到"
|
|
}
|
|
var settles []models.ErpFundSettle
|
|
_, _ = models.Orm.QueryTable(new(models.ErpFundSettle)).
|
|
Filter("fund_bill_id", id).OrderBy("id").All(&settles)
|
|
billIDs := make([]uint64, 0, len(settles))
|
|
for _, s := range settles {
|
|
billIDs = append(billIDs, s.PartnerBillID)
|
|
}
|
|
bills := []models.ErpPartnerBill{}
|
|
if len(billIDs) > 0 {
|
|
_, _ = models.Orm.QueryTable(new(models.ErpPartnerBill)).
|
|
Filter("id__in", billIDs).All(&bills)
|
|
}
|
|
fund.Settles = settles
|
|
return map[string]interface{}{"fund": fund, "bills": bills}, 200, ""
|
|
}
|
|
|
|
// erpFundSaveCore 新建/修改收付款草稿(草稿态才可改,确认后只能作废重开)
|
|
func erpFundSaveCore(a erpActor, p erpFundPayload) (uint64, string, int, string) {
|
|
tid := a.Tid
|
|
if p.FundType < models.ErpFundReceive || p.FundType > models.ErpFundExpense {
|
|
return 0, "", 400, "收付款方式无效"
|
|
}
|
|
if p.Amount <= 0 {
|
|
return 0, "", 400, "金额必须大于0"
|
|
}
|
|
if (p.FundType == models.ErpFundReceive || p.FundType == models.ErpFundPay) && p.PartnerID == 0 {
|
|
return 0, "", 400, "收款/付款必须选择往来单位"
|
|
}
|
|
partnerType := ""
|
|
if p.FundType == models.ErpFundReceive {
|
|
partnerType = "customer"
|
|
} else if p.FundType == models.ErpFundPay {
|
|
partnerType = "supplier"
|
|
}
|
|
name := erpPartnerName(partnerType, p.PartnerID)
|
|
if p.PartnerID > 0 && name == "" {
|
|
return 0, "", 400, erpPartnerLabel(partnerType) + "不存在"
|
|
}
|
|
bizDate := time.Now()
|
|
if p.BizDate != "" {
|
|
if t, e := time.ParseInLocation("2006-01-02", p.BizDate, time.Local); e == nil {
|
|
bizDate = t
|
|
}
|
|
}
|
|
method := strings.TrimSpace(p.PayMethod)
|
|
if method == "" {
|
|
method = "cash"
|
|
}
|
|
now := time.Now()
|
|
if p.ID > 0 {
|
|
var fund models.ErpFundBill
|
|
if err := models.Orm.QueryTable(new(models.ErpFundBill)).
|
|
Filter("id", p.ID).Filter("tenant_id", tid).
|
|
Filter("delete_time__isnull", true).One(&fund); err != nil {
|
|
return 0, "", 404, "收付款单未找到"
|
|
}
|
|
if fund.Status != 0 {
|
|
return 0, "", 400, "已确认的收付款单不可修改"
|
|
}
|
|
if _, err := models.Orm.QueryTable(new(models.ErpFundBill)).Filter("id", p.ID).
|
|
Update(orm.Params{
|
|
"fund_type": p.FundType, "partner_type": partnerType, "partner_id": p.PartnerID,
|
|
"partner_name": name, "amount": p.Amount, "pay_method": method,
|
|
"pay_account": p.PayAccount, "biz_date": bizDate, "remark": p.Remark,
|
|
"update_time": now,
|
|
}); err != nil {
|
|
return 0, "", 500, "保存失败: " + err.Error()
|
|
}
|
|
return p.ID, fund.FundNo, 200, ""
|
|
}
|
|
no, e := erp.GenerateFundNo(tid, p.FundType)
|
|
if e != nil {
|
|
return 0, "", 500, e.Error()
|
|
}
|
|
fund := models.ErpFundBill{
|
|
TenantID: tid, FundNo: no, FundType: p.FundType,
|
|
PartnerType: partnerType, PartnerID: p.PartnerID, PartnerName: name,
|
|
Amount: p.Amount, PayMethod: method, PayAccount: p.PayAccount,
|
|
BizDate: bizDate, Status: 0, Remark: p.Remark,
|
|
CreateUserID: fmt.Sprintf("%d", a.UID), CreateUserName: a.Name,
|
|
CreateTime: now, UpdateTime: now,
|
|
}
|
|
id, err := models.Orm.Insert(&fund)
|
|
if err != nil {
|
|
return 0, "", 500, "创建失败: " + err.Error()
|
|
}
|
|
return uint64(id), no, 200, ""
|
|
}
|
|
|
|
// erpFundConfirmCore 确认收付款并核销;settles 为空时按到期日自动 FIFO
|
|
func erpFundConfirmCore(a erpActor, id uint64, settles []erp.SettleItem) (int, string) {
|
|
if id == 0 {
|
|
return 400, "无效的ID"
|
|
}
|
|
if err := erp.ConfirmFundBill(id, a.Tid, settles, a.Name); err != nil {
|
|
return 400, err.Error()
|
|
}
|
|
return 200, ""
|
|
}
|
|
|
|
// erpFundVoidCore 作废收付款单(已核销的往来账余额同步回滚)
|
|
func erpFundVoidCore(a erpActor, id uint64) (int, string) {
|
|
if id == 0 {
|
|
return 400, "无效的ID"
|
|
}
|
|
if err := erp.VoidFundBill(id, a.Tid); err != nil {
|
|
return 400, err.Error()
|
|
}
|
|
return 200, ""
|
|
}
|
|
|
|
// erpFundDeleteCore 删除收付款单,仅草稿可删
|
|
func erpFundDeleteCore(a erpActor, id uint64) (int, string) {
|
|
if id == 0 {
|
|
return 400, "无效的ID"
|
|
}
|
|
var fund models.ErpFundBill
|
|
if err := models.Orm.QueryTable(new(models.ErpFundBill)).
|
|
Filter("id", id).Filter("tenant_id", a.Tid).
|
|
Filter("delete_time__isnull", true).One(&fund); err != nil {
|
|
return 404, "收付款单未找到"
|
|
}
|
|
if fund.Status != 0 {
|
|
return 400, "只有草稿状态的收付款单可以删除"
|
|
}
|
|
now := time.Now()
|
|
if _, err := models.Orm.QueryTable(new(models.ErpFundBill)).Filter("id", id).
|
|
Update(orm.Params{"delete_time": now, "update_time": now}); err != nil {
|
|
return 500, "删除失败: " + err.Error()
|
|
}
|
|
return 200, ""
|
|
}
|
|
|
|
// erpFundOpenBillsCore 收款/付款时可核销的往来账(前端据此勾选)
|
|
func erpFundOpenBillsCore(a erpActor, fundType int8, partnerID uint64) ([]map[string]interface{}, int, string) {
|
|
billType := int8(models.ErpBillReceivable)
|
|
if fundType == 2 {
|
|
billType = models.ErpBillPayable
|
|
}
|
|
qs := models.Orm.QueryTable(new(models.ErpPartnerBill)).
|
|
Filter("tenant_id", a.Tid).Filter("bill_type", billType).
|
|
Filter("status__lt", 2).Filter("amount__gt", 0)
|
|
if partnerID > 0 {
|
|
qs = qs.Filter("partner_id", partnerID)
|
|
}
|
|
var rows []models.ErpPartnerBill
|
|
_, _ = qs.OrderBy("due_date", "bill_date", "id").Limit(200).All(&rows)
|
|
out := make([]map[string]interface{}, 0, len(rows))
|
|
for _, b := range rows {
|
|
out = append(out, map[string]interface{}{
|
|
"id": b.ID, "source_doc_no": b.SourceDocNo, "bill_date": b.BillDate,
|
|
"due_date": b.DueDate, "amount": b.Amount, "settled_amount": b.SettledAmount,
|
|
"balance": round2f(b.Amount - b.SettledAmount), "partner_name": b.PartnerName,
|
|
})
|
|
}
|
|
return out, 200, ""
|
|
}
|
|
|
|
// erpCashDayRow 按日汇总的资金流水
|
|
type erpCashDayRow struct {
|
|
Date string `json:"date"`
|
|
In float64 `json:"in"`
|
|
Out float64 `json:"out"`
|
|
Net float64 `json:"net"`
|
|
}
|
|
|
|
// erpCashFlowCore 资金流水(只统计实际收付,不含单据生成的往来账)
|
|
func erpCashFlowCore(a erpActor, from, to time.Time) (map[string]interface{}, int, string) {
|
|
var rows []models.ErpFundBill
|
|
_, _ = models.Orm.QueryTable(new(models.ErpFundBill)).
|
|
Filter("tenant_id", a.Tid).Filter("status", 1).
|
|
Filter("biz_date__gte", from).Filter("biz_date__lte", to).
|
|
OrderBy("biz_date", "id").All(&rows)
|
|
|
|
days := map[string]*erpCashDayRow{}
|
|
var totalIn, totalOut float64
|
|
for _, f := range rows {
|
|
d := f.BizDate.Format("2006-01-02")
|
|
if days[d] == nil {
|
|
days[d] = &erpCashDayRow{Date: d}
|
|
}
|
|
if f.FundType == models.ErpFundReceive || f.FundType == models.ErpFundOtherIn {
|
|
days[d].In = round2f(days[d].In + f.Amount)
|
|
totalIn += f.Amount
|
|
} else {
|
|
days[d].Out = round2f(days[d].Out + f.Amount)
|
|
totalOut += f.Amount
|
|
}
|
|
}
|
|
list := make([]*erpCashDayRow, 0, len(days))
|
|
keys := make([]string, 0, len(days))
|
|
for k := range days {
|
|
keys = append(keys, k)
|
|
}
|
|
sort.Strings(keys)
|
|
for _, k := range keys {
|
|
r := days[k]
|
|
r.Net = round2f(r.In - r.Out)
|
|
list = append(list, r)
|
|
}
|
|
return map[string]interface{}{
|
|
"list": list, "total_in": round2f(totalIn), "total_out": round2f(totalOut),
|
|
"net": round2f(totalIn - totalOut),
|
|
}, 200, ""
|
|
}
|
|
|
|
// erpPartnerSumRow 往来单位对账汇总行
|
|
type erpPartnerSumRow struct {
|
|
PartnerID uint64 `json:"partner_id"`
|
|
PartnerType string `json:"partner_type"`
|
|
PartnerName string `json:"partner_name"`
|
|
RecvTotal float64 `json:"recv_total"`
|
|
RecvOpen float64 `json:"recv_open"`
|
|
PayTotal float64 `json:"pay_total"`
|
|
PayOpen float64 `json:"pay_open"`
|
|
LastBillDate string `json:"last_bill_date"`
|
|
}
|
|
|
|
// erpPartnerSummaryCore 往来单位对账汇总(partnerType 为空=不限)
|
|
func erpPartnerSummaryCore(a erpActor, partnerType string) (map[string]interface{}, int, string) {
|
|
var bills []models.ErpPartnerBill
|
|
_, _ = models.Orm.QueryTable(new(models.ErpPartnerBill)).
|
|
Filter("tenant_id", a.Tid).All(&bills)
|
|
m := map[string]*erpPartnerSumRow{}
|
|
for _, b := range bills {
|
|
k := b.PartnerType + ":" + fmt.Sprintf("%d", b.PartnerID)
|
|
r := m[k]
|
|
if r == nil {
|
|
r = &erpPartnerSumRow{PartnerID: b.PartnerID, PartnerType: b.PartnerType, PartnerName: b.PartnerName}
|
|
m[k] = r
|
|
}
|
|
if b.BillDate.Format("2006-01-02") > r.LastBillDate {
|
|
r.LastBillDate = b.BillDate.Format("2006-01-02")
|
|
}
|
|
if b.BillType == models.ErpBillReceivable {
|
|
r.RecvTotal = round2f(r.RecvTotal + b.Amount)
|
|
if b.Status < 2 {
|
|
r.RecvOpen = round2f(r.RecvOpen + b.Amount - b.SettledAmount)
|
|
}
|
|
} else {
|
|
r.PayTotal = round2f(r.PayTotal + b.Amount)
|
|
if b.Status < 2 {
|
|
r.PayOpen = round2f(r.PayOpen + b.Amount - b.SettledAmount)
|
|
}
|
|
}
|
|
}
|
|
list := make([]*erpPartnerSumRow, 0, len(m))
|
|
for _, r := range m {
|
|
if partnerType != "" && r.PartnerType != partnerType {
|
|
continue
|
|
}
|
|
list = append(list, r)
|
|
}
|
|
return map[string]interface{}{"list": list}, 200, ""
|
|
}
|