仿金蝶,物料庫存系統設計與實現思路

蘇小林發表於2019-05-11

公司最近也在開發庫存系統,就拿業界比較成功的金蝶來分析學習,提升自身的業務水平 庫存系統最重要的就是入庫與出庫,成本與利潤的計算

入庫操作核心流程

入庫操作時序圖
出庫操作核心流程
出庫操作時序圖

參與的角色

出入庫操作參與的角色可以在金蝶系統裡的核算專案裡看到,這個角色非常重要,涉及到後面的表結構設計

仿金蝶,物料庫存系統設計與實現思路
可以看到有很多的角色,因為金蝶不僅僅是個庫存系統,同時也是一個完整財務系統,找出庫存系統不可缺少的角色有以下幾個

  1. 供應商:庫存系統把物料出庫給供應商,供應商供貨給系統就入庫
  2. 物料:參與庫存計算的最小單位
  3. 倉庫:同一個物料可以同時出現在多個倉庫中,但是出入庫的物件一次只能選擇一個倉庫

在計量單位裡可以管理物料的單位

仿金蝶,物料庫存系統設計與實現思路
特別注意這個計量單位裡的換算率,比如上面的盒的換算率是10,個是預設單位,就表示1盒可以換成10個

還有一個發起出入庫方的角色(一般是一個公司發起出入庫),這裡出入庫都是作者,表結構上暫時忽略

出入庫

開啟倉庫管理->採購入庫/銷售出庫,拿採購入庫舉例

仿金蝶,物料庫存系統設計與實現思路

可以看到入庫單核心的欄位有這些

  1. 供應商(這些物料從哪裡採購的)
  2. 入庫日期
  3. 編號(不可修改,自動生成)
  4. 入庫的物料
  5. 入庫的倉庫
  6. 實收的數量
  7. 實收的數量的單位
  8. 單價
  9. 金額

計價方式

在金蝶的新增物料介面,可以檢視當前系統支援的計價方法

仿金蝶,物料庫存系統設計與實現思路

目前業界廣泛使用有:

  1. 移動平均法
  2. 先進先出法 其它的計價方式目前使用得比較少了,有興趣的可以去了解下會計知識 目前對先進先出法比較熟悉,就拿先進先出的計價方法舉例了

表結構設計

  1. 出入庫單據表
  2. 出入庫單據裡關聯的物料表
  3. 批次物料庫存金額結存表
  4. 批次物料庫存出入庫記錄表
  5. 供應商表
  6. 物料表
  7. 倉庫表
  8. 單位表
  9. 庫存表 可以看到這個最簡單的批次庫存表也有9張表了 下面由作者認為的從簡單到複雜的順序來設計表,設計一個滿足出入庫的最小表結構

單位表

目前不考慮換算率,也就不參與庫存的換算,所以單位表的欄位就比較簡單了 sql如下:

CREATE TABLE `unit` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `code` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '物品編碼',
  `name` varchar(128) NOT NULL DEFAULT '' COMMENT '名稱',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `name` (`name`) USING BTREE,
  UNIQUE KEY `code` (`code`) USING BTREE COMMENT '`'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='計量單位';
複製程式碼

供應商表

供應商在系統裡是出入庫的物件,入庫的物料是從供應商那裡買來的,出庫的物料是退貨給供應商

CREATE TABLE `supply` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(45) NOT NULL DEFAULT '' COMMENT '名稱',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='供應商表';
複製程式碼

倉庫表

倉庫表用來標識物料存在在那個倉庫,同一個物料可能存在在多個倉庫,入庫時必須選擇物料入到那個庫

CREATE TABLE `warehouse` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
  `organization_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '門店id',
  `name` varchar(32) NOT NULL DEFAULT '' COMMENT '庫房名稱',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='庫房資訊表';
複製程式碼

庫存表

用來記錄物料在不同倉庫的庫存,入庫和出庫時需要把庫存數量從批次裡同步到庫存表裡

CREATE TABLE `inventory` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
  `warehouse_id` bigint(20) unsigned NOT NULL COMMENT '庫房ID',
  `material_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '物料id',
  `count` decimal(16,2) NOT NULL DEFAULT '0.00' COMMENT '總庫存',
  `lock_count` decimal(16,2) NOT NULL DEFAULT '0.00' COMMENT '佔用庫存',
  `available_count` decimal(16,2) NOT NULL DEFAULT '0.00' COMMENT '可用庫存',
  `cost_amount` decimal(16,4) NOT NULL DEFAULT '0.0000' COMMENT '成本總金額',
  `updated_at` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '更新時間',
  `created_at` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '建立時間',
  `deleted_at` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '刪除時間',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_group_id_label_id_relation_id_type` (`warehouse_id`,`material_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='倉庫庫存表';
複製程式碼

物料表

物料是庫存操作的基本物件

CREATE TABLE `material` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `material_code` varchar(45) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '物品編碼',
  `name` varchar(45) NOT NULL COMMENT '名稱',
  `category_id` int(11) unsigned NOT NULL COMMENT '所屬分類',
  `category_name` varchar(45) NOT NULL COMMENT '分類名稱',
  `unit_weight` decimal(10,4) unsigned NOT NULL DEFAULT '0.0000' COMMENT '單位重量',
  `base_unit_id` bigint(20) DEFAULT NULL COMMENT '主單位id',
  `base_unit_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '' COMMENT '主單位名稱',
  `updated_at` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '更新日期',
  `created_at` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '建立時期',
  `deleted_at` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '刪除時間',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='物料';
複製程式碼

出入庫單據表

單據表用來記錄有多少個出入庫單,和單據的一些元資訊,比如這個單據的發起的供應商,操作人,單據金額,單據裡的物料的數量等

CREATE TABLE `in_out` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `type` tinyint(2) unsigned NOT NULL DEFAULT '0' COMMENT '1:採購訂單 2:採購收貨單 3:採購退貨單',
  `in_out_code` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '單號',
  `warehouse_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '倉庫ID',
  `warehouse_name` varchar(64) NOT NULL DEFAULT '' COMMENT '倉庫名稱',
  `supply_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '供應商id',
  `supply_name` varchar(64) NOT NULL DEFAULT '' COMMENT '供應商名稱',
  `address` varchar(45) NOT NULL DEFAULT '' COMMENT '交貨地址',
  `count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '物料數量',
  `amount_total` decimal(18,8) unsigned NOT NULL DEFAULT '0.00000000' COMMENT '當前單據總金額',
  `amount_count` decimal(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '當前單據總數量',
  `created_at` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '建立時間',
  `updated_at` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '更新時間',
  `deleted_at` int(11) NOT NULL DEFAULT '0' COMMENT '刪除時間',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_group_id_expense_sn` (`in_out_code`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='單據表';
複製程式碼

出入庫單據物料關聯表

記錄出入庫裡的物料的詳細資訊,比如物料的名稱,編碼,單位,數量,單價,金額,稅額等參與庫存計算的核心欄位

CREATE TABLE `in_out_detail` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
  `warehouse_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '倉庫ID',
  `warehouse_name` varchar(62) NOT NULL DEFAULT '' COMMENT '倉庫名稱',
  `in_out_code` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '單號',
  `in_out_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '單號ID',
  `in_out_type` tinyint(4) DEFAULT NULL COMMENT '單據型別',
  `material_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '關聯ID',
  `material_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '關聯物料名稱',
  `material_code` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '關聯物料sn',
  `unit_basic_name` varchar(32) NOT NULL DEFAULT '' COMMENT '基本單位名稱',
  `unit_basic_value` decimal(10,3) NOT NULL DEFAULT '1.000' COMMENT '基本單位數值',
  `unit_basic_count` decimal(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '主單位數量',
  `unit_basic_price` decimal(14,4) unsigned NOT NULL DEFAULT '0.0000' COMMENT '主單位不含稅單價',
  `unit_basic_tax_price` decimal(14,4) unsigned NOT NULL DEFAULT '0.0000' COMMENT '主單位的含稅單價',
  `unit_basic_total` decimal(18,8) unsigned NOT NULL DEFAULT '0.00000000' COMMENT '主單位不含稅金額',
  `unit_basic_tax_total` decimal(18,8) NOT NULL DEFAULT '0.00000000' COMMENT '主單位含稅金額',
  `tax` decimal(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '稅率',
  `tax_total` decimal(18,8) unsigned NOT NULL DEFAULT '0.00000000' COMMENT '稅額',
  `production_at` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '生產日期',
  `created_at` int(11) unsigned NOT NULL DEFAULT '0',
  `updated_at` int(11) unsigned NOT NULL DEFAULT '0',
  `deleted_at` int(11) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_in_out_id_material_id` (`in_out_id`,`material_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1110 DEFAULT CHARSET=utf8 COMMENT='單據物料關聯表';
複製程式碼

物料批次表

這個批次表就是記錄物料的所有的批次當前的庫存狀態,物料一個批次的庫存理論上最多用到0庫存.

CREATE TABLE `batch` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `code` int(11) DEFAULT NULL COMMENT '批次程式碼',
  `warehouse_id` bigint(20) DEFAULT NULL COMMENT '倉庫id',
  `in_type` int(4) DEFAULT NULL COMMENT '入庫單型別',
  `in_id` bigint(20) DEFAULT NULL COMMENT '入庫單的id',
  `material_id` bigint(20) DEFAULT NULL COMMENT '物料、菜品、套餐關聯id',
  `end_tax_price` decimal(14,4) DEFAULT '0.0000' COMMENT '當前含稅單價',
  `end_price` decimal(14,4) DEFAULT '0.0000' COMMENT '當前不含稅單價',
  `end_count` decimal(10,2) DEFAULT '0.00' COMMENT '當前 主單位庫存數量 要減去佔用數量',
  `end_total_amount` decimal(18,8) DEFAULT '0.00000000' COMMENT '當前不含稅總金額(發生單據後這個值會發生變化)',
  `end_tax_total_amount` decimal(18,8) DEFAULT '0.00000000' COMMENT '當前含稅總金額',
  `end_tax_total` decimal(18,8) DEFAULT '0.00000000' COMMENT '當前結存稅額',
  `cost_tax_price` decimal(14,4) DEFAULT '0.0000' COMMENT '原含稅單價',
  `cost_price` decimal(14,4) DEFAULT '0.0000' COMMENT '原不含稅單價',
  `cost_count` decimal(10,2) DEFAULT '0.00' COMMENT '原主單位庫存數量',
  `cost_total_amount` decimal(18,8) DEFAULT '0.00000000' COMMENT '原不含稅總金額',
  `cost_tax_total_amount` decimal(18,8) DEFAULT '0.00000000' COMMENT '原含稅總金額',
  `cost_tax_total` decimal(18,8) DEFAULT '0.00000000' COMMENT '原稅額',
  `gross_profit` decimal(18,8) DEFAULT '0.00000000' COMMENT '利潤金額(含稅:入-成本/出-成本)',
  `lock_count` decimal(10,2) DEFAULT '0.00' COMMENT '佔用/鎖定數量',
  `production_at` int(11) DEFAULT NULL COMMENT '生產日期',
  `status` tinyint(1) DEFAULT '1' COMMENT '凍結為0 非凍結為1',
  `remark` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '備註',
  `updated_at` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '更新時間',
  `created_at` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '建立時間',
  `deleted_at` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '刪除時間',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='批次表';
複製程式碼

物料批次快照表

記錄每次批次物料表發生變化後的快照

CREATE TABLE `batch_snapshot` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `batch_id` bigint(20) DEFAULT NULL,
  `in_out_detail_type` int(4) DEFAULT NULL COMMENT '單據詳情型別',
  `in_out_detail_id` bigint(20) DEFAULT NULL COMMENT '入庫單價',
  `in_count` decimal(12,4) DEFAULT '0.0000' COMMENT '入庫數量',
  `in_total_amount` decimal(18,8) DEFAULT NULL,
  `in_tax_total` decimal(18,8) DEFAULT '0.00000000' COMMENT '稅額',
  `in_tax_total_amount` decimal(18,8) DEFAULT '0.00000000' COMMENT '入庫含稅金額',
  `out_price` decimal(14,4) DEFAULT '0.0000' COMMENT '出庫單價',
  `out_count` decimal(10,2) DEFAULT '0.00' COMMENT '出庫數量',
  `out_total_amount` decimal(18,8) DEFAULT '0.00000000' COMMENT '出庫未含稅金額',
  `out_tax_total` decimal(18,8) DEFAULT '0.00000000' COMMENT '出庫稅額',
  `out_tax_total_amount` decimal(18,8) DEFAULT '0.00000000' COMMENT '出庫含稅金額',
  `out_cost_tax_price` decimal(14,4) DEFAULT '0.0000' COMMENT '出庫成本單價(含稅)',
  `out_cost_price` decimal(14,4) DEFAULT '0.0000' COMMENT '出庫成本單價(不含稅)',
  `out_cost_total_amount` decimal(18,8) DEFAULT '0.00000000' COMMENT '出庫成本含稅金額',
  `out_cost_tax_total_amount` decimal(18,8) DEFAULT '0.00000000' COMMENT '出庫成本不含稅金額',
  `out_cost_tax_total` decimal(18,8) DEFAULT '0.00000000' COMMENT '出庫成本稅額',
  `end_price` decimal(14,4) DEFAULT '0.0000' COMMENT '當前未含稅單價',
  `end_tax_price` decimal(14,4) DEFAULT '0.0000' COMMENT '當前含稅單價',
  `end_count` decimal(10,2) DEFAULT '0.00' COMMENT '當前結存數量',
  `end_total_amount` decimal(18,8) DEFAULT '0.00000000' COMMENT '當前結存未含稅金額',
  `end_tax_total_amount` decimal(18,8) unsigned DEFAULT '0000000000.00000000' COMMENT '當前結存含稅金額',
  `end_tax_total` decimal(18,8) DEFAULT '0.00000000' COMMENT '當前結存稅額',
  `updated_at` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '更新時間',
  `created_at` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '建立時間',
  `deleted_at` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '刪除時間',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='批次快照表';
複製程式碼

核心演算法

庫存系統裡只要影響庫存和金額的操作都可以算作庫存的核心演算法,其中最重要的就是物料的計價方法了,因為每次出入庫都會用到這個物料的計價方法,而不同的計價方法又會直接影響到庫存的成本和利潤

成本計算:成本是含稅的,所以計算成本時需要把稅也計算在內 1. 使用者輸入系統的成本是不含稅的,那麼系統需要用稅點算出稅額加到成本里 2. 使用者輸入系統的成本是含稅的,那麼系統需要減掉稅點得到不含稅的成本

一些注意的點

金額在mysql使用decimal型別儲存,在java中使用BigDecimal型別表示 批次快照表只是記錄批次物料的庫存快照,不參與庫存和成本的計算。

持續更新...

相關文章