149 lines
4.3 KiB
TypeScript
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.

// 坯布入库事务处理 Edge Function
// 确保 completed_quantity 和 inventory_records 数据一致性
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
Deno.serve(async (req) => {
// CORS 预检
if (req.method === 'OPTIONS') {
return new Response('ok', {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
},
});
}
const corsHeaders = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
};
try {
const body = await req.json();
const {
planId,
quantity,
rolls,
warehouseId,
warehouseLocation,
operatorId,
pricePerMeter,
} = body;
// 参数验证
if (!planId || !quantity || quantity <= 0) {
return new Response(
JSON.stringify({ error: '缺少必要参数或数量无效' }),
{ status: 400, headers: corsHeaders }
);
}
// 获取认证信息
const authHeader = req.headers.get('Authorization') || '';
// 创建管理员客户端(绕过 RLS
const supabaseAdmin = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!,
);
// 开始事务处理
// 1. 获取当前计划信息
const { data: plan, error: planError } = await supabaseAdmin
.from('production_plans')
.select('completed_quantity, target_quantity, purchaser_id')
.eq('id', planId)
.maybeSingle();
if (planError || !plan) {
return new Response(
JSON.stringify({ error: '获取计划信息失败: ' + (planError?.message || '计划不存在') }),
{ status: 404, headers: corsHeaders }
);
}
// 2. 计算新的已完成数量
const newCompletedQuantity = (plan.completed_quantity || 0) + quantity;
// 3. 检查是否超过目标数量
if (newCompletedQuantity > plan.target_quantity) {
return new Response(
JSON.stringify({ error: `入库数量超过剩余数量 (${plan.target_quantity - (plan.completed_quantity || 0)}米)` }),
{ status: 400, headers: corsHeaders }
);
}
const now = new Date().toISOString();
// 4. 更新计划的 completed_quantity
const { error: updateError } = await supabaseAdmin
.from('production_plans')
.update({ completed_quantity: newCompletedQuantity })
.eq('id', planId);
if (updateError) {
return new Response(
JSON.stringify({ error: '更新计划数量失败: ' + updateError.message }),
{ status: 500, headers: corsHeaders }
);
}
// 5. 创建入库记录
const insertData: any = {
plan_id: planId,
quantity: quantity,
rolls: rolls || 0,
warehouse_location: warehouseLocation || '',
operator_id: operatorId,
price_per_meter: pricePerMeter || 0,
created_at: now,
};
if (warehouseId) {
insertData.warehouse_id = warehouseId;
}
const { data: inventoryRecord, error: insertError } = await supabaseAdmin
.from('inventory_records')
.insert(insertData)
.select()
.single();
if (insertError) {
// 如果入库记录创建失败,需要回滚 completed_quantity
// 注意:这里简化处理,实际生产环境应使用数据库事务
await supabaseAdmin
.from('production_plans')
.update({ completed_quantity: plan.completed_quantity })
.eq('id', planId);
return new Response(
JSON.stringify({ error: '创建入库记录失败: ' + insertError.message }),
{ status: 500, headers: corsHeaders }
);
}
// 6. 返回成功结果
return new Response(
JSON.stringify({
success: true,
data: {
inventoryRecord,
completedQuantity: newCompletedQuantity,
progress: Math.round((newCompletedQuantity / plan.target_quantity) * 100),
},
}),
{ headers: corsHeaders }
);
} catch (error) {
const message = error instanceof Error ? error.message : 'Unknown error';
return new Response(
JSON.stringify({ error: '服务器错误: ' + message }),
{ status: 500, headers: corsHeaders }
);
}
});