|
|
|
// 文件:Services/WarehouseDataApiService.cs
|
|
|
|
using System.Net.Http;
|
|
|
|
using System.Text;
|
|
|
|
using System.Text.Json;
|
|
|
|
using System.Text.Json.Nodes;
|
|
|
|
using IndustrialControl.ViewModels;
|
|
|
|
|
|
|
|
namespace IndustrialControl.Services;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 真实接口实现,风格对齐 WorkOrderApi
|
|
|
|
/// </summary>
|
|
|
|
public sealed class InboundMaterialService : IInboundMaterialService
|
|
|
|
{
|
|
|
|
public readonly HttpClient _http;
|
|
|
|
public readonly string _inboundListEndpoint;
|
|
|
|
public readonly string _detailEndpoint;
|
|
|
|
public readonly string _scanDetailEndpoint;
|
|
|
|
// 新增:扫码入库端点
|
|
|
|
public readonly string _scanByBarcodeEndpoint;
|
|
|
|
public readonly string _scanConfirmEndpoint;
|
|
|
|
public readonly string _cancelScanEndpoint;
|
|
|
|
public readonly string _confirmInstockEndpoint;
|
|
|
|
public readonly string _judgeScanAllEndpoint;
|
|
|
|
|
|
|
|
public InboundMaterialService(HttpClient http, IConfigLoader configLoader)
|
|
|
|
{
|
|
|
|
_http = http;
|
|
|
|
|
|
|
|
JsonNode cfg = configLoader.Load();
|
|
|
|
|
|
|
|
// ⭐ 新增:读取 baseUrl 或 ip+port
|
|
|
|
var baseUrl =
|
|
|
|
(string?)cfg?["server"]?["baseUrl"]
|
|
|
|
?? BuildBaseUrl(cfg?["server"]?["ipAddress"], cfg?["server"]?["port"]);
|
|
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(baseUrl))
|
|
|
|
throw new InvalidOperationException("后端基础地址未配置:请在 appconfig.json 配置 server.baseUrl 或 server.ipAddress + server.port");
|
|
|
|
|
|
|
|
if (_http.BaseAddress is null)
|
|
|
|
_http.BaseAddress = new Uri(baseUrl, UriKind.Absolute);
|
|
|
|
|
|
|
|
// 下面保持原来的相对路径读取(不变)
|
|
|
|
_inboundListEndpoint =
|
|
|
|
(string?)cfg?["apiEndpoints"]?["inbound"]?["list"] ??
|
|
|
|
(string?)cfg?["apiEndpoints"]?["getInStock"] ??
|
|
|
|
"/normalService/pda/wmsMaterialInstock/getInStock";
|
|
|
|
|
|
|
|
_detailEndpoint =
|
|
|
|
(string?)cfg?["apiEndpoints"]?["inbound"]?["detail"] ??
|
|
|
|
"/normalService/pda/wmsMaterialInstock/getInStockDetail";
|
|
|
|
|
|
|
|
_scanDetailEndpoint =
|
|
|
|
(string?)cfg?["apiEndpoints"]?["inbound"]?["scanDetail"] ??
|
|
|
|
"/normalService/pda/wmsMaterialInstock/getInStockScanDetail";
|
|
|
|
|
|
|
|
_scanByBarcodeEndpoint =
|
|
|
|
(string?)cfg?["apiEndpoints"]?["inbound"]?["scanByBarcode"] ??
|
|
|
|
"/normalService/pda/wmsMaterialInstock/getInStockByBarcode";
|
|
|
|
|
|
|
|
_scanConfirmEndpoint =
|
|
|
|
(string?)cfg?["apiEndpoints"]?["inbound"]?["scanConfirm"] ??
|
|
|
|
"/normalService/pda/wmsMaterialInstock/scanConfirm";
|
|
|
|
|
|
|
|
_cancelScanEndpoint =
|
|
|
|
(string?)cfg?["apiEndpoints"]?["inbound"]?["cancelScan"] ??
|
|
|
|
"/normalService/pda/wmsMaterialInstock/cancelScan";
|
|
|
|
|
|
|
|
_confirmInstockEndpoint =
|
|
|
|
(string?)cfg?["apiEndpoints"]?["inbound"]?["confirm"] ??
|
|
|
|
"/normalService/pda/wmsMaterialInstock/confirm";
|
|
|
|
|
|
|
|
_judgeScanAllEndpoint =
|
|
|
|
(string?)cfg?["apiEndpoints"]?["inbound"]?["judgeScanAll"] ??
|
|
|
|
"/normalService/pda/wmsMaterialInstock/judgeInstockDetailScanAll";
|
|
|
|
}
|
|
|
|
|
|
|
|
// ⭐ 新增:拼接 ip + port → baseUrl
|
|
|
|
private static string? BuildBaseUrl(JsonNode? ipNode, JsonNode? portNode)
|
|
|
|
{
|
|
|
|
string? ip = ipNode?.ToString().Trim();
|
|
|
|
string? port = portNode?.ToString().Trim();
|
|
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(ip)) return null;
|
|
|
|
|
|
|
|
// 如果没带 http:// 或 https://,默认 http://
|
|
|
|
var hasScheme = ip.StartsWith("http://", StringComparison.OrdinalIgnoreCase)
|
|
|
|
|| ip.StartsWith("https://", StringComparison.OrdinalIgnoreCase);
|
|
|
|
var host = hasScheme ? ip : $"http://{ip}";
|
|
|
|
|
|
|
|
return string.IsNullOrEmpty(port) ? host : $"{host}:{port}";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public async Task<IEnumerable<InboundOrderSummary>> ListInboundOrdersAsync(
|
|
|
|
string? orderNoOrBarcode,
|
|
|
|
DateTime startDate,
|
|
|
|
DateTime endDate,
|
|
|
|
string orderType,
|
|
|
|
string[] orderTypeList,
|
|
|
|
CancellationToken ct = default)
|
|
|
|
{
|
|
|
|
// 结束时间扩到当天 23:59:59,避免把当日数据排除
|
|
|
|
var begin = startDate.ToString("yyyy-MM-dd 00:00:00");
|
|
|
|
var end = endDate.ToString("yyyy-MM-dd 23:59:59");
|
|
|
|
|
|
|
|
// 用 KVP 列表(不要 Dictionary)→ 规避 WinRT generic + AOT 警告
|
|
|
|
var pairs = new List<KeyValuePair<string, string>>
|
|
|
|
{
|
|
|
|
new("createdTimeBegin", begin),
|
|
|
|
new("createdTimeEnd", end),
|
|
|
|
new("pageNo", "1"),
|
|
|
|
new("pageSize","10")
|
|
|
|
// 如需统计总数:new("searchCount", "true")
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(orderNoOrBarcode))
|
|
|
|
pairs.Add(new("instockNo", orderNoOrBarcode.Trim()));
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(orderType))
|
|
|
|
pairs.Add(new("orderType", orderType));
|
|
|
|
|
|
|
|
if (orderTypeList is { Length: > 0 })
|
|
|
|
pairs.Add(new("orderTypeList", string.Join(",", orderTypeList)));
|
|
|
|
|
|
|
|
// 交给 BCL 编码(比手写 Escape 安全)
|
|
|
|
using var form = new FormUrlEncodedContent(pairs);
|
|
|
|
var qs = await form.ReadAsStringAsync(ct);
|
|
|
|
var url = _inboundListEndpoint + "?" + qs;
|
|
|
|
|
|
|
|
using var req = new HttpRequestMessage(HttpMethod.Get, url);
|
|
|
|
using var resp = await _http.SendAsync(req, ct);
|
|
|
|
var json = await resp.Content.ReadAsStringAsync(ct);
|
|
|
|
|
|
|
|
if (!resp.IsSuccessStatusCode)
|
|
|
|
return Enumerable.Empty<InboundOrderSummary>();
|
|
|
|
|
|
|
|
var opt = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
|
|
|
var dto = JsonSerializer.Deserialize<GetInStockPageResp>(json, opt);
|
|
|
|
|
|
|
|
var records = dto?.result?.records;
|
|
|
|
if (dto?.success != true || records is null || records.Count == 0)
|
|
|
|
return Enumerable.Empty<InboundOrderSummary>();
|
|
|
|
|
|
|
|
return records.Select(x => new InboundOrderSummary(
|
|
|
|
instockId: x.id ?? "",
|
|
|
|
instockNo: x.instockNo ?? "",
|
|
|
|
orderType: x.orderType ?? "",
|
|
|
|
orderTypeName: x.orderTypeName ?? "",
|
|
|
|
purchaseNo: x.purchaseNo ?? "",
|
|
|
|
arrivalNo: x.arrivalNo ?? "",
|
|
|
|
supplierName: x.supplierName ?? "",
|
|
|
|
createdTime: x.createdTime ?? ""
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public async Task<IReadOnlyList<InboundPendingRow>> GetInStockDetailAsync(
|
|
|
|
string instockId, CancellationToken ct = default)
|
|
|
|
{
|
|
|
|
// ✅ 文档为 GET + x-www-form-urlencoded,参数名是小写 instockId
|
|
|
|
var url = $"{_detailEndpoint}?instockId={Uri.EscapeDataString(instockId)}";
|
|
|
|
using var req = new HttpRequestMessage(HttpMethod.Get, url);
|
|
|
|
|
|
|
|
using var res = await _http.SendAsync(req, ct).ConfigureAwait(false);
|
|
|
|
res.EnsureSuccessStatusCode();
|
|
|
|
|
|
|
|
var json = await res.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
|
|
|
|
var opt = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
|
|
|
var dto = JsonSerializer.Deserialize<GetInStockDetailResp>(json, opt);
|
|
|
|
|
|
|
|
if (dto?.success != true || dto.result is null || dto.result.Count == 0)
|
|
|
|
return Array.Empty<InboundPendingRow>();
|
|
|
|
|
|
|
|
static int ToIntSafe(string? s)
|
|
|
|
{
|
|
|
|
if (string.IsNullOrWhiteSpace(s)) return 0;
|
|
|
|
s = s.Trim().Replace(",", "");
|
|
|
|
return int.TryParse(s, out var v) ? v : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ⚠️ 接口没有 barcode,这里先用空串;如需展示可以改成 x.materialCode 或 x.stockBatch
|
|
|
|
var list = dto.result.Select(x => new InboundPendingRow(
|
|
|
|
Barcode: string.Empty, // 或 $"{x.materialCode}" / $"{x.stockBatch}"
|
|
|
|
DetailId: x.id ?? string.Empty, // ← 改为接口的 id
|
|
|
|
Location: x.location ?? string.Empty,
|
|
|
|
MaterialName: x.materialName ?? string.Empty,
|
|
|
|
PendingQty: ToIntSafe(x.instockQty), // ← 预计数量
|
|
|
|
ScannedQty: ToIntSafe(x.qty), // ← 已扫描量
|
|
|
|
Spec: x.spec ?? string.Empty
|
|
|
|
)).ToList();
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
public async Task<IReadOnlyList<InboundScannedRow>> GetInStockScanDetailAsync(
|
|
|
|
string instockId,
|
|
|
|
CancellationToken ct = default)
|
|
|
|
{
|
|
|
|
// 文档为 GET + x-www-form-urlencoded,这里用 query 传递(关键在大小写常为 InstockId)
|
|
|
|
var url = $"{_scanDetailEndpoint}?InstockId={Uri.EscapeDataString(instockId)}";
|
|
|
|
using var req = new HttpRequestMessage(HttpMethod.Get, url);
|
|
|
|
|
|
|
|
using var res = await _http.SendAsync(req, ct).ConfigureAwait(false);
|
|
|
|
res.EnsureSuccessStatusCode();
|
|
|
|
|
|
|
|
var json = await res.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
|
|
|
|
|
|
|
|
var opt = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
|
|
|
var dto = JsonSerializer.Deserialize<GetInStockScanDetailResp>(json, opt);
|
|
|
|
|
|
|
|
if (dto?.success != true || dto.result is null || dto.result.Count == 0)
|
|
|
|
return Array.Empty<InboundScannedRow>();
|
|
|
|
|
|
|
|
static int ToIntSafe(string? s)
|
|
|
|
{
|
|
|
|
if (string.IsNullOrWhiteSpace(s)) return 0;
|
|
|
|
// 去除千分位、空格
|
|
|
|
s = s.Trim().Replace(",", "");
|
|
|
|
return int.TryParse(s, out var v) ? v : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 映射:InstockId <- id(截图注释“入库单明细主键id”)
|
|
|
|
var list = dto.result.Select(x => new InboundScannedRow(
|
|
|
|
Barcode: (x.barcode ?? string.Empty).Trim(),
|
|
|
|
DetailId: (x.id ?? string.Empty).Trim(),
|
|
|
|
Location: (x.location ?? string.Empty).Trim(),
|
|
|
|
MaterialName: (x.materialName ?? string.Empty).Trim(),
|
|
|
|
Qty: ToIntSafe(x.qty),
|
|
|
|
Spec: (x.spec ?? string.Empty).Trim(),
|
|
|
|
ScanStatus :x.scanStatus ?? false,
|
|
|
|
WarehouseCode :x.warehouseCode?.Trim()
|
|
|
|
)).ToList();
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ========= 扫码入库实现 =========
|
|
|
|
public async Task<SimpleOk> InStockByBarcodeAsync(string instockId, string barcode, CancellationToken ct = default)
|
|
|
|
{
|
|
|
|
var body = JsonSerializer.Serialize(new { barcode, instockId });
|
|
|
|
using var req = new HttpRequestMessage(HttpMethod.Post, _scanByBarcodeEndpoint)
|
|
|
|
{
|
|
|
|
Content = new StringContent(body, Encoding.UTF8, "application/json")
|
|
|
|
};
|
|
|
|
|
|
|
|
using var res = await _http.SendAsync(req, ct);
|
|
|
|
var json = await res.Content.ReadAsStringAsync(ct);
|
|
|
|
var opt = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
|
|
|
var dto = JsonSerializer.Deserialize<ScanByBarcodeResp>(json, opt);
|
|
|
|
|
|
|
|
// 按文档:以 success 判断;message 作为失败提示
|
|
|
|
var ok = dto?.success == true;
|
|
|
|
return new SimpleOk(ok, dto?.message);
|
|
|
|
}
|
|
|
|
public async Task<SimpleOk> ScanConfirmAsync(string instockId, CancellationToken ct = default)
|
|
|
|
{
|
|
|
|
var bodyJson = JsonSerializer.Serialize(new { instockId });
|
|
|
|
using var req = new HttpRequestMessage(HttpMethod.Post, _scanConfirmEndpoint)
|
|
|
|
{
|
|
|
|
Content = new StringContent(bodyJson, Encoding.UTF8, "application/json")
|
|
|
|
};
|
|
|
|
|
|
|
|
using var res = await _http.SendAsync(req, ct);
|
|
|
|
var json = await res.Content.ReadAsStringAsync(ct);
|
|
|
|
|
|
|
|
var opt = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
|
|
|
var dto = JsonSerializer.Deserialize<ScanConfirmResp>(json, opt);
|
|
|
|
|
|
|
|
var ok = dto?.success == true;
|
|
|
|
return new SimpleOk(ok, dto?.message);
|
|
|
|
}
|
|
|
|
|
|
|
|
public async Task<SimpleOk> CancelScanAsync(string instockId, CancellationToken ct = default)
|
|
|
|
{
|
|
|
|
var bodyJson = JsonSerializer.Serialize(new { instockId });
|
|
|
|
using var req = new HttpRequestMessage(HttpMethod.Post, _cancelScanEndpoint)
|
|
|
|
{
|
|
|
|
Content = new StringContent(bodyJson, Encoding.UTF8, "application/json")
|
|
|
|
};
|
|
|
|
|
|
|
|
using var res = await _http.SendAsync(req, ct);
|
|
|
|
var json = await res.Content.ReadAsStringAsync(ct);
|
|
|
|
|
|
|
|
var opt = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
|
|
|
var dto = JsonSerializer.Deserialize<CancelScanResp>(json, opt);
|
|
|
|
|
|
|
|
var ok = dto?.success == true;
|
|
|
|
return new SimpleOk(ok, dto?.message);
|
|
|
|
}
|
|
|
|
|
|
|
|
public async Task<SimpleOk> ConfirmInstockAsync(string instockId, CancellationToken ct = default)
|
|
|
|
{
|
|
|
|
var bodyJson = JsonSerializer.Serialize(new { instockId });
|
|
|
|
using var req = new HttpRequestMessage(HttpMethod.Post, _confirmInstockEndpoint)
|
|
|
|
{
|
|
|
|
Content = new StringContent(bodyJson, Encoding.UTF8, "application/json")
|
|
|
|
};
|
|
|
|
|
|
|
|
using var res = await _http.SendAsync(req, ct);
|
|
|
|
var json = await res.Content.ReadAsStringAsync(ct);
|
|
|
|
|
|
|
|
var opt = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
|
|
|
var dto = JsonSerializer.Deserialize<ConfirmResp>(json, opt);
|
|
|
|
|
|
|
|
var ok = dto?.success == true;
|
|
|
|
return new SimpleOk(ok, dto?.message);
|
|
|
|
}
|
|
|
|
public async Task<bool> JudgeInstockDetailScanAllAsync(string instockId, CancellationToken ct = default)
|
|
|
|
{
|
|
|
|
var url = $"{_judgeScanAllEndpoint}?id={Uri.EscapeDataString(instockId)}";
|
|
|
|
using var req = new HttpRequestMessage(HttpMethod.Get, url);
|
|
|
|
using var res = await _http.SendAsync(req, ct);
|
|
|
|
var json = await res.Content.ReadAsStringAsync(ct);
|
|
|
|
|
|
|
|
var opt = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
|
|
|
|
var dto = JsonSerializer.Deserialize<JudgeScanAllResp>(json, opt);
|
|
|
|
|
|
|
|
// 按文档:看 result(true/false);若接口异常或无 result,则返回 false 让前端提示/二次确认
|
|
|
|
return dto?.result == true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ====== DTO(按接口示例字段) ======
|
|
|
|
public class GetInStockReq
|
|
|
|
{
|
|
|
|
public string? createdTime { get; set; }
|
|
|
|
public string? endTime { get; set; }
|
|
|
|
public string? instockNo { get; set; }
|
|
|
|
public string? orderType { get; set; }
|
|
|
|
public string? startTime { get; set; }
|
|
|
|
}
|
|
|
|
|
|
|
|
public class GetInStockResp
|
|
|
|
{
|
|
|
|
public int code { get; set; }
|
|
|
|
public long costTime { get; set; }
|
|
|
|
public string? message { get; set; }
|
|
|
|
public bool success { get; set; }
|
|
|
|
public List<GetInStockItem>? result { get; set; }
|
|
|
|
}
|
|
|
|
|
|
|
|
public class GetInStockItem
|
|
|
|
{
|
|
|
|
public string? arrivalNo { get; set; }
|
|
|
|
public string? createdTime { get; set; }
|
|
|
|
public string? instockId { get; set; }
|
|
|
|
public string? instockNo { get; set; }
|
|
|
|
public string? orderType { get; set; }
|
|
|
|
public string? purchaseNo { get; set; }
|
|
|
|
public string? supplierName { get; set; }
|
|
|
|
}
|
|
|
|
public sealed class GetInStockDetailResp
|
|
|
|
{
|
|
|
|
public bool success { get; set; }
|
|
|
|
public string? message { get; set; }
|
|
|
|
public int? code { get; set; }
|
|
|
|
public List<GetInStockDetailItem>? result { get; set; }
|
|
|
|
public int? costTime { get; set; }
|
|
|
|
}
|
|
|
|
public sealed class GetInStockDetailItem
|
|
|
|
{
|
|
|
|
public string? id { get; set; } // 入库单明细主键id
|
|
|
|
public string? instockNo { get; set; } // 入库单号
|
|
|
|
public string? materialCode { get; set; }
|
|
|
|
public string? materialName { get; set; }
|
|
|
|
public string? spec { get; set; }
|
|
|
|
public string? stockBatch { get; set; }
|
|
|
|
public string? instockQty { get; set; } // 预计数量(字符串/可能为空)
|
|
|
|
public string? instockWarehouseCode { get; set; } // 入库仓库编码
|
|
|
|
public string? location { get; set; } // 内点库位
|
|
|
|
public string? qty { get; set; } // 已扫描量(字符串/可能为空)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public class ScanRow
|
|
|
|
{
|
|
|
|
public string? barcode { get; set; }
|
|
|
|
public string? instockId { get; set; }
|
|
|
|
public string? location { get; set; }
|
|
|
|
public string? materialName { get; set; }
|
|
|
|
public string? qty { get; set; }
|
|
|
|
public string? spec { get; set; }
|
|
|
|
}
|
|
|
|
|
|
|
|
public class ScanByBarcodeResp
|
|
|
|
{
|
|
|
|
public int code { get; set; }
|
|
|
|
public long costTime { get; set; }
|
|
|
|
public string? message { get; set; }
|
|
|
|
public object? result { get; set; } // 文档里 result 只是 bool/无结构,这里占位
|
|
|
|
public bool success { get; set; }
|
|
|
|
}
|
|
|
|
public class ScanConfirmResp
|
|
|
|
{
|
|
|
|
public int code { get; set; }
|
|
|
|
public long costTime { get; set; }
|
|
|
|
public string? message { get; set; }
|
|
|
|
public object? result { get; set; }
|
|
|
|
public bool success { get; set; }
|
|
|
|
}
|
|
|
|
public class CancelScanResp
|
|
|
|
{
|
|
|
|
public int code { get; set; }
|
|
|
|
public long costTime { get; set; }
|
|
|
|
public string? message { get; set; }
|
|
|
|
public object? result { get; set; }
|
|
|
|
public bool success { get; set; }
|
|
|
|
}
|
|
|
|
public class ConfirmResp
|
|
|
|
{
|
|
|
|
public int code { get; set; }
|
|
|
|
public long costTime { get; set; }
|
|
|
|
public string? message { get; set; }
|
|
|
|
public object? result { get; set; }
|
|
|
|
public bool success { get; set; }
|
|
|
|
}
|
|
|
|
public class JudgeScanAllResp
|
|
|
|
{
|
|
|
|
public int code { get; set; }
|
|
|
|
public long costTime { get; set; }
|
|
|
|
public string? message { get; set; }
|
|
|
|
public bool success { get; set; }
|
|
|
|
public bool? result { get; set; } // 文档中为布尔
|
|
|
|
}
|
|
|
|
public class GetInStockPageResp
|
|
|
|
{
|
|
|
|
public int code { get; set; }
|
|
|
|
public long costTime { get; set; }
|
|
|
|
public string? message { get; set; }
|
|
|
|
public bool success { get; set; }
|
|
|
|
public GetInStockPageData? result { get; set; }
|
|
|
|
}
|
|
|
|
|
|
|
|
public class GetInStockPageData
|
|
|
|
{
|
|
|
|
public int pageNo { get; set; }
|
|
|
|
public int pageSize { get; set; }
|
|
|
|
public long total { get; set; }
|
|
|
|
public List<GetInStockRecord> records { get; set; } = new();
|
|
|
|
}
|
|
|
|
|
|
|
|
public class GetInStockRecord
|
|
|
|
{
|
|
|
|
public string? id { get; set; }
|
|
|
|
public string? instockNo { get; set; }
|
|
|
|
public string? orderType { get; set; }
|
|
|
|
public string? orderTypeName { get; set; }
|
|
|
|
public string? supplierName { get; set; }
|
|
|
|
public string? arrivalNo { get; set; }
|
|
|
|
public string? purchaseNo { get; set; }
|
|
|
|
public string? createdTime { get; set; }
|
|
|
|
}
|
|
|
|
public sealed class GetInStockScanDetailResp
|
|
|
|
{
|
|
|
|
public bool success { get; set; }
|
|
|
|
public string? message { get; set; }
|
|
|
|
public int? code { get; set; }
|
|
|
|
public List<GetInStockScanDetailItem>? result { get; set; }
|
|
|
|
public int? costTime { get; set; }
|
|
|
|
}
|
|
|
|
|
|
|
|
public sealed class GetInStockScanDetailItem
|
|
|
|
{
|
|
|
|
public string? id { get; set; } // 入库单明细主键 id
|
|
|
|
public string? barcode { get; set; }
|
|
|
|
public string? materialName { get; set; }
|
|
|
|
public string? spec { get; set; }
|
|
|
|
public string? qty { get; set; } // 可能是 null 或 “数字字符串”
|
|
|
|
public string? warehouseCode { get; set; }
|
|
|
|
public string? location { get; set; }
|
|
|
|
public bool? scanStatus { get; set; } // 可能为 null,按 false 处理
|
|
|
|
}
|
|
|
|
|
|
|
|
|
...
|
...
|
|