kae_mihara e3f6fa236d
feat:improve product yarn ratio workflow (#5)
* feat: support product yarn batches

* feat: improve product yarn ratio workflow

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-05 08:06:28 +09:00

141 lines
3.7 KiB
Go
Raw Permalink 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.

package logic
import (
"database/sql"
"encoding/json"
"fmt"
"math"
"strconv"
"strings"
"muyu-apiserver/model"
"muyu-apiserver/rpc/inventory/pb"
)
func nullString(v string) sql.NullString {
return sql.NullString{String: v, Valid: v != ""}
}
func nullableJSON(v string) sql.NullString {
v = strings.TrimSpace(v)
return sql.NullString{String: v, Valid: v != ""}
}
func parseDecimalString(v string) float64 {
n, _ := strconv.ParseFloat(strings.TrimSpace(v), 64)
return n
}
type yarnRatioPayload struct {
Warp []yarnRatioItem `json:"warp"`
Weft []yarnRatioItem `json:"weft"`
}
type yarnRatioItem struct {
YarnID string `json:"yarn_id"`
YarnId string `json:"yarnId"`
Ratio float64 `json:"ratio"`
}
func (i yarnRatioItem) yarnID() string {
if i.YarnID != "" {
return i.YarnID
}
return i.YarnId
}
func validateProductBatchInput(batch *pb.ProductBatchInput) error {
if batch == nil {
return nil
}
return validateYarnRatio(batch.YarnRatio)
}
func validateYarnRatio(raw string) error {
raw = strings.TrimSpace(raw)
if raw == "" {
return nil
}
var payload yarnRatioPayload
if err := json.Unmarshal([]byte(raw), &payload); err != nil {
return fmt.Errorf("纱线配比格式无效")
}
if err := validateYarnRatioSide("经线", payload.Warp); err != nil {
return err
}
return validateYarnRatioSide("纬线", payload.Weft)
}
func validateYarnRatioSide(label string, items []yarnRatioItem) error {
if len(items) == 0 {
return nil
}
total := 0
for _, item := range items {
if strings.TrimSpace(item.yarnID()) == "" {
return fmt.Errorf("%s纱线不能为空", label)
}
if item.Ratio < 1 || item.Ratio > 10 || math.Trunc(item.Ratio) != item.Ratio {
return fmt.Errorf("%s使用配比必须为 1-10 的整数", label)
}
total += int(item.Ratio)
}
if total != 10 {
return fmt.Errorf("%s配比合计必须为 10当前为 %d", label, total)
}
return nil
}
func batchInputToModelFields(batch *pb.ProductBatchInput, target *model.InvProductBatch) error {
if batch == nil {
target.ProductionProcess = nullString(defaultProcess)
return nil
}
if err := validateProductBatchInput(batch); err != nil {
return err
}
target.YarnRatio = nullableJSON(batch.YarnRatio)
target.WarpWeightGM = parseDecimalString(batch.WarpWeightGM)
target.WeftWeightGM = parseDecimalString(batch.WeftWeightGM)
process := strings.TrimSpace(batch.ProductionProcess)
if process == "" {
process = defaultProcess
}
target.ProductionProcess = nullString(process)
target.Remark = nullString(batch.Remark)
return nil
}
func batchToPb(batch *model.InvProductBatch) *pb.ProductBatchInfo {
return &pb.ProductBatchInfo{
BatchId: batch.BatchId,
ProductId: batch.ProductId,
BatchNo: batch.BatchNo,
YarnRatio: batch.YarnRatio.String,
WarpWeightGM: fmt.Sprintf("%.4f", batch.WarpWeightGM),
WeftWeightGM: fmt.Sprintf("%.4f", batch.WeftWeightGM),
ProductionProcess: batch.ProductionProcess.String,
Remark: batch.Remark.String,
Status: batch.Status,
CreatedAt: batch.CreatedAt.Format("2006-01-02 15:04:05"),
UpdatedAt: batch.UpdatedAt.Format("2006-01-02 15:04:05"),
}
}
func productToPb(product *model.InvProduct) *pb.ProductInfo {
return &pb.ProductInfo{
ProductId: product.ProductId,
ProductName: product.ProductName,
ImageUrl: product.ImageUrl,
Spec: product.Spec,
Color: product.Color,
SalesPrice: fmt.Sprintf("%.2f", product.SalesPrice),
Remark: product.Remark.String,
Status: product.Status,
CreatedAt: product.CreatedAt.Format("2006-01-02 15:04:05"),
UpdatedAt: product.UpdatedAt.Format("2006-01-02 15:04:05"),
ColorNo: product.ColorNo,
ProductCode: product.ProductCode,
}
}