【问题标题】:How to track product cost over time for a POS system?如何跟踪 POS 系统随时间推移的产品成本?
【发布时间】:2015-03-08 22:40:48
【问题描述】:

我正在设计一个销售点“POS”数据库,同时使用 MySQL 作为我的 DBMS。

在将产品添加到产品数据库时,我会添加产品名称(即“可口可乐 2.L”)和 UPC 代码、成本、价格、部门、供应商和数量。

如果我收到 1000 瓶的订单,每瓶花费 1 美元

假设 2 个月后,我只剩下 100 瓶库存“我的成本是 100 美元”。现在,我又订购了 5,000 瓶,但这次因为我订购了 5,000 瓶,供应商每瓶给我 0.10 美元的折扣(即每瓶 0.90 美元。)所以,我第二次订购的成本是 4500 美元。我想确保我非常准确地跟踪我的利润。因此,我以 1 美元购买的 100 个我希望能够以 1 美元的成本单独跟踪它们,并以 0.90 美元的成本跟踪新订单。

我目前跟踪每个销售项目成本的方式,通过从产品表中读取当前成本并将其与销售价格、transaction_id 和 product_id 一起保存在 sales_transactions_items 表中。

我现在遇到的问题是,当我收到 5000 瓶时,我将成本从 1 美元更改为 0.90 美元,这使我的利润增加了(100 瓶 x 每瓶节省 0.10 美元)100x0.10 = 10 美元的利润我实际上并没有获利。售出数量后,出现这种差异是因为数量价值达到了 5100 瓶,其中 100 瓶以 1 美元购买,5000 瓶以每瓶 0.90 美元购买。

我的问题:我该如何解决这个问题,我才能真正了解每件商品花了我多少钱。

【问题讨论】:

  • 您需要另一张桌子。一个用于产品,一个用于购买
  • 这如何帮助我确定前 1000 个以 1 美元购买,而 5000 个以 0.90 美元购买? item_id 和 UPC 码还是一样的
  • 在表格中记录您的购买日期/时间、成本、购买的商品数量和未售出的商品数量。用日期/时间、商品数量和这些商品的成本记录您的销售额。您可能想要运行 FIFO 系统,以便您首先出售最旧的物品。如果您销售 300 件商品,其中 100 件以旧价格出售,200 件以新价格出售,您在内部记录了两条销售商品行,每个采购价对应一条。如果这些物品是可以单独追踪的(有一个序列号——不像普通的一瓶可乐,但非常像普通的电脑),那么你又会以不同的方式做事。
  • 通常情况下,我会在列上应用约束:CHECK(number >= 0)。这或多或少是标准的 SQL(概念是标准的;我需要查看符号),但我不知道 MySQL 是否支持声明和执行此类约束。至于同时更新:这就是事务和 DBMS 的用途。如果您使用的是适当的引擎(我相信是 InnoDB for MySQL),那么 DBMS 会自动处理它。您在单个事务中为销售执行所有修改操作,DBMS 防止事务相互干扰。
  • 有多种可能性——没有一个是微不足道的。如果您有收据编号,您可以在销售表中查找它,这通常会告诉您哪个是价格——如果发票/收据详细信息足够详尽,您可以确定哪个批次的价格销售属于。显然,如果收据标识拆分批次,您必须选择退回的物料来自哪个批次。是不是越早越晚越便宜越贵?如果您没有收据,或者收据详细信息不充分,您可能最终会猜到它来自哪个批次。

标签: mysql database database-design point-of-sale


【解决方案1】:

这是一个足够通用但过于简单的示例,说明您的架构可能是什么样子

CREATE TABLE products
(
  `id` int not null auto_increment primary key, 
  `name` varchar(13), 
  `price` decimal(12, 2), -- current sale price. You might want to extract it into it's own table `prices`
  ...
);

CREATE TABLE orders
(
  `id` int not null auto_increment primary key, 
  `date` date,
  ...
);

CREATE TABLE order_items
(
  `id` int not null auto_increment primary key, 
  `order_id` int not null, 
  `product_id` int, 
  `quantity` decimal(12, 3), 
  `cost` decimal(12, 2),
  foreign key (`order_id`) references orders (id),
  foreign key (`product_id`) references products (id)
);

CREATE TABLE sales
(
  `id` int not null auto_increment primary key, 
  `date` datetime,
  ...
);

CREATE TABLE sale_items
(
  `id` int not null auto_increment primary key, 
  `sale_id` int not null, 
  `product_id` int, 
  `quantity` decimal(12, 3), 
  `price` decimal(12, 2),
  foreign key (`sale_id`) references sales (id),
  foreign key (`product_id`) references products (id)
);

这是一个SQLFiddle演示

这使您能够独立跟踪成本和销售额。


一种计算总销售额、总实际成本和每个产品的利润的方法

SELECT product_id, p.name, sales_quantity, sales_total, cost_total, sales_total - cost_total margin
  FROM
(
  SELECT product_id, sales_quantity, sales_total, SUM(
    CASE WHEN sales_quantity >= running_quantity 
           THEN cost * quantity
         WHEN sales_quantity BETWEEN running_quantity - quantity AND running_quantity
           THEN cost * (sales_quantity - (running_quantity - quantity))
          ELSE 0 
     END) cost_total
    FROM
  (
    SELECT s.*, o.cost, o.quantity, o.running_quantity
      FROM
    (
      SELECT product_id, 
             SUM(quantity * price) sales_total, 
             SUM(quantity) sales_quantity
      FROM sale_items
     GROUP BY product_id
    ) s JOIN 
    (
      SELECT product_id, cost, quantity, (
        SELECT SUM(quantity)
          FROM order_items
         WHERE product_id = i.product_id
           AND order_id <= i.order_id
         ) running_quantity
        FROM order_items i
    ) o
        ON s.product_id = o.product_id
  ) q
   GROUP BY product_id, sales_quantity, sales_total
) q JOIN products p
    ON q.product_id = p.id

样本输出:

| PRODUCT_ID |姓名 |销售_数量 |销售总额 | COST_TOTAL |保证金 | |------------|---------------|----|--- ----------|------------|--------| | 1 |可口可乐 2.L | 150 | 187.5 | 145 | 42.5 |

这是一个SQLFiddle演示

您可能会看到,在示例中,售出的 150 瓶中的前 100 瓶售价 100 美元(1*100 美元),其余 50 瓶售价 45 美元(0.9*50)

【讨论】:

  • 我仍然不清楚这种设计将如何帮助我确定每个订单的成本。所以我卖了 2 件 product_id = 1 一件花了我 1 美元,另一件花了我 0.9 美元 这个设置如何帮助我确定我的成本是 1.90 美元?我确实看到您正在单独捕获购买/订单,但我如何确定成本?我将如何编写查询来计算我们的真实成本?
  • 如果您将成本字段添加到sale_items,您可以将两个或更多成本分配给一个项目。见FIDDLE
  • 价格值应该很容易获得,因为它存储在产品表中。但是,在将新记录插入sale_item 表之前,您如何计算出cost 的值?
  • @Mike 有帮助吗?
  • @peterm 是的。我仍在努力寻找解决此问题的最佳方法。我非常感谢您的回答和帮助,但我尽量避免编写如此复杂的查询,除非我也有。我正在尝试遵循上面 Jonathan Leffler 的建议,这将使我能够跟踪交易级别的成本,还可以让我使用 FIFO 系统找出有多少物品的成本
【解决方案2】:
Declare @FromDate DateTime=GetDate()
declare @ToDate DateTime=GetDate()
Select ToDateProfit.ProductID,ToDateProfit.Name,ToDateProfit.sales_quantity-   ISNULL(FromDateProfit.sales_quantity,0) as Sales_Quantity
,ToDateProfit.sales_total-ISNULL(FromDateProfit.sales_total,0) as Sales_Total
,ToDateProfit.cost_total-ISNULL(FromDateProfit.cost_total,0) as Cost_Total
,ToDateProfit.margin-ISNULL(FromDateProfit.margin,0) as Margin
 From
(
SELECT P.ProductID, p.name, sales_quantity, sales_total, cost_total, sales_total - cost_total margin
  FROM
(
  SELECT productid, sales_quantity, sales_total, SUM(
CASE WHEN sales_quantity >= running_quantity 
       THEN  PurchasePrice* quantity
     WHEN sales_quantity BETWEEN running_quantity - quantity AND running_quantity
       THEN PurchasePrice * (sales_quantity - (running_quantity - quantity))
      ELSE 0 
 END) cost_total
FROM
  (
SELECT s.*, o.PurchasePrice, o.quantity, o.running_quantity
  FROM
(
  SELECT ProductID, 
         SUM((quantity * UnitPrice)/ExchangeRate) sales_total, 
         SUM(quantity) sales_quantity
  FROM SaleDetail
  Inner Join Sale on Sale.SaleID=SaleDetail.SaleID
 where Convert(Date,Sale.SaleDate)<=Convert(date,@ToDate) --(must minus saledate <FromDate            (GetDate() is ToDate)         )
 GROUP BY ProductID
) s JOIN 
    (
  SELECT  productid, BuyingPrice/ExchangeRate as PurchasePrice, quantity, (
    SELECT SUM(quantity)
      FROM PurchaseDetail
     inner join Purchase Pur on Pur.PurchaseID=PurchaseDetail.PurchaseID 
     WHERE productid = i.productid
       AND Pur.Date <= PurI.date ----Fifo (if want lifo change <= to >=)
     ) running_quantity
    FROM PurchaseDetail i
    Inner join Purchase PurI on PurI.PurchaseID=i.PurchaseID
) o
ON s.productid = o.productid
)q
GROUP BY productid, sales_quantity, sales_total
) q JOIN product p
ON q.ProductID = p.ProductID
)ToDateProfit 
Left Join
(
SELECT P.ProductID, p.name, sales_quantity, sales_total, cost_total, sales_total - cost_total margin
FROM
(
SELECT productid, sales_quantity, sales_total, SUM(
CASE WHEN sales_quantity >= running_quantity 
       THEN  PurchasePrice* quantity
     WHEN sales_quantity BETWEEN running_quantity - quantity AND running_quantity
       THEN PurchasePrice * (sales_quantity - (running_quantity - quantity))
      ELSE 0 
 END) cost_total
FROM
(
SELECT s.*, o.PurchasePrice, o.quantity, o.running_quantity
FROM
(
SELECT ProductID, 
         SUM((quantity * UnitPrice)/ExchangeRate) sales_total, 
         SUM(quantity) sales_quantity
  FROM SaleDetail
  Inner Join Sale on Sale.SaleID=SaleDetail.SaleID
 where Convert(Date,Sale.SaleDate)<Convert(date,@FromDate) --(must minus saledate <FromDate            (GetDate() is ToDate)         )
 GROUP BY ProductID
) s JOIN 
(
  SELECT  productid, BuyingPrice/ExchangeRate as PurchasePrice, quantity, (
    SELECT SUM(quantity)
      FROM PurchaseDetail
     inner join Purchase Pur on Pur.PurchaseID=PurchaseDetail.PurchaseID 
     WHERE productid = i.productid
       AND Pur.Date <= PurI.date ----Fifo (if want lifo change <= to >=)
     ) running_quantity
    FROM PurchaseDetail i
    Inner join Purchase PurI on PurI.PurchaseID=i.PurchaseID 
) o    ON s.productid = o.productid 
) q 
GROUP BY productid, sales_quantity, sales_total
) q JOIN product p
ON q.ProductID = p.ProductID
)FromDateProfit on FromDateProfit.ProductID=ToDateProfit.ProductID
Inner Join ---------Only Product
(
Select Product.ProductID From Product
Inner Join SaleDetail On SaleDetail.ProductID=Product.ProductID
Inner Join Sale On Sale.SaleID=SaleDetail.SaleID
Where CONVERT(Date,SaleDate)>=CONVERT(Date,@FromDate) And  CONVERT(Date,SaleDate)<=CONVERT(Date,@ToDate)
Group By Product.ProductID)SP On SP.ProductID=ToDateProfit.ProductID

【讨论】:

    【解决方案3】:

    “我想确保我非常准确地跟踪我的利润。因此,我以 1 美元购买的 100 个我希望能够以 1 美元的成本单独跟踪它们,并以 0.90 美元的成本跟踪新订单。” - 这不是必需的。您必须计算当前平均价格并使用它计算利润。你没有每瓶的序列号,因此即使你想知道每件商品的利润——你也做不到。而且从所有者的角度来看,重要的是要知道可口可乐的总利润,而不是“这瓶是0.50,那瓶是0.45”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-01
      • 2022-06-16
      • 1970-01-01
      • 2014-05-07
      • 1970-01-01
      • 2019-01-04
      • 2021-07-28
      相关资源
      最近更新 更多