การสร้างใบแจ้งหนี้และการติดตาม


11

ทุก 2 สัปดาห์ระบบจะสร้างใบแจ้งหนี้ให้กับ บริษัท

บริษัท จะได้รับใบแจ้งหนี้ในวันที่ 1 และ 16 ของทุกเดือน (มันจะทำงานผ่าน Cron Job ทุก 2 สัปดาห์มันสแกนผ่านตารางคำสั่งซื้อแล้วเพิ่มลงในตาราง 'ใบแจ้งหนี้' มีทางเลือกอื่นหรือไม่)

มีรายการคำสั่งซื้อของลูกค้าในordersตารางและยังระบุ บริษัท ที่เป็นของ ( orders.company_id)

invoiceตารางการคำนวณค่าใช้จ่ายทั้งหมดของการสั่งซื้อจากordersตาราง

ฉันกำลังพยายามหาวิธีการออกแบบการติดตามใบแจ้งหนี้ที่สมเหตุสมผล บริษัท บางครั้งจะต้องส่งค่าธรรมเนียมหรือบางครั้งฉันส่งค่าธรรมเนียม ( invoice.amount)

ฉันต้องการติดตามใบแจ้งหนี้ด้วยสิ่งต่อไปนี้:

  • เมื่อ บริษัท ส่งจำนวนเงินให้ฉัน
  • ฉันส่งจำนวนเงินให้ บริษัท เมื่อใด
  • ได้รับเงินจำนวนเท่าใดจาก บริษัท
  • ฉันส่งไปยัง บริษัท เท่าไร
  • ฉันได้รับเงินเต็มจำนวนหรือไม่ (ถ้าไม่ฉันต้องอัปเดตสิ่งใดใน Db)
  • สถานะใบแจ้งหนี้ (ส่งใบแจ้งหนี้, ยกเลิก, จำนวนเงินที่ได้รับ, จำนวนเงินที่ส่ง)

นี่คือการออกแบบฐานข้อมูลฉันมาด้วย:

ตาราง บริษัท

mysql> select * from company;
+----+-----------+
| id | name      |
+----+-----------+
|  1 | Company A |
|  2 | Company B |
+----+-----------+

ลูกค้าสามารถเลือก บริษัท ได้จากเว็บไซต์ของฉัน

ตารางคำสั่งซื้อ

mysql> select * from orders;
+----+---------+------------+------------+---------------------+-----------+
| id | user_id | company_id | total_cost | order_date          | status_id |
+----+---------+------------+------------+---------------------+-----------+
|  1 |       5 |          2 |      25.00 | 2012-02-03 23:30:24 |         1 |
|  2 |       7 |          2 |      30.00 | 2012-02-13 18:06:12 |         1 |
+----+---------+------------+------------+---------------------+-----------+

ลูกค้าสองรายได้สั่งซื้อผลิตภัณฑ์จากบริษัท B ( orders.company_id = 2) ฉันรู้ว่าฟิลด์คำสั่งซื้อไม่เพียงพอทำให้คุณง่ายขึ้น

ตาราง orders_products

mysql> select * from orders_products;
+----+----------+------------+--------------+-------+
| id | order_id | product_id | product_name | cost  |
+----+----------+------------+--------------+-------+
|  1 |        1 |         34 | Chair        | 10.00 |
|  2 |        1 |         25 | TV           | 10.00 |
|  3 |        1 |         27 | Desk         |  2.50 |
|  4 |        1 |         36 | Laptop       |  2.50 |
|  5 |        2 |         75 | PHP Book     | 25.00 |
|  6 |        2 |         74 | MySQL Book   |  5.00 |
+----+----------+------------+--------------+-------+

รายการสินค้าที่ลูกค้าสั่ง

ตารางใบแจ้งหนี้

mysql> select * from invoice;
+----+------------+------------+---------------------+--------+-----------+
| id | company_id | invoice_no | invoice_date        | amount | status_id |
+----+------------+------------+---------------------+--------+-----------+
|  7 |          2 |        123 | 2012-02-16 23:59:59 |  55.00 |         1 |
+----+------------+------------+---------------------+--------+-----------+

นี่คือที่ฉันค่อนข้างติดอยู่ในการออกแบบตารางใบแจ้งหนี้ ฉันไม่แน่ใจว่าควรจะทำอย่างไร ใบแจ้งหนี้จะถูกสร้างขึ้นทุก 2 สัปดาห์ จากตัวอย่างผลลัพธ์invoice.amountคือ 55.00 เนื่องจากมันถูกคำนวณจากorders.company_id = 2ตาราง

หากinvoice.amountเป็น -50.00 (ลบ) หมายถึง บริษัท จะต้องส่งจำนวนค่าธรรมเนียมให้ฉัน

หากinvoice.amountเป็น 50.00 แสดงว่าฉันต้องส่งค่าธรรมเนียม บริษัท

status_id อาจเป็น: (1) ส่งใบแจ้งหนี้, (2) ยกเลิก, (3) เสร็จสมบูรณ์

ฉันจำเป็นต้องเพิ่มinvoice_idฟิลด์ในordersตารางหรือไม่ อัปเดตorders.invoice_idฟิลด์เมื่อแทรกแถวลงในตาราง 'ใบแจ้งหนี้'

ตารางใบแจ้งหนี้ _payment

mysql> select * from invoice_payment;
+----+------------+-----------------+-------------+---------------------+---------------------+
| id | invoice_id | amount_received | amount_sent | date_received       | date_sent           |
+----+------------+-----------------+-------------+---------------------+---------------------+
|  1 |          1 |            0.00 |       55.00 | 0000-00-00 00:00:00 | 2012-02-18 22:20:53 |
+----+------------+-----------------+-------------+---------------------+---------------------+

ที่นี่ฉันสามารถติดตามและอัปเดตธุรกรรม .. การชำระเงินจะดำเนินการผ่าน BACS

นี่เป็นการออกแบบตารางที่ดีหรือฉันต้องปรับปรุงอะไร ฉันควรเพิ่มฟิลด์และตารางใด

หากมีการสร้างใบแจ้งหนี้และภายหลังฉันจำเป็นต้องทำการเปลี่ยนแปลงorders_productsหรือordersตาราง - ควรคำนวณinvoice.amountฟิลด์ใหม่หรือไม่ (ฉันจะใช้ PHP / MySQL)

SQL Dump :

CREATE TABLE IF NOT EXISTS `company` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(25) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;

INSERT INTO `company` (`id`, `name`) VALUES
(1, 'Company A'),
(2, 'Company B');

CREATE TABLE IF NOT EXISTS `invoice` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `company_id` int(11) NOT NULL,
  `invoice_no` int(11) NOT NULL,
  `invoice_date` datetime NOT NULL,
  `amount` decimal(6,2) NOT NULL,
  `status_id` tinyint(1) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=8 ;


INSERT INTO `invoice` (`id`, `company_id`, `invoice_no`, `invoice_date`, `amount`, `status_id`) VALUES
(7, 2, 123, '2012-02-16 23:59:59', '55.00', 1);


CREATE TABLE IF NOT EXISTS `invoice_payment` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `invoice_id` int(11) NOT NULL,
  `amount_received` decimal(6,2) NOT NULL,
  `amount_sent` decimal(6,2) NOT NULL,
  `date_received` datetime NOT NULL,
  `date_sent` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;

INSERT INTO `invoice_payment` (`id`, `invoice_id`, `amount_received`, `amount_sent`, `date_received`, `date_sent`) VALUES
(1, 1, '0.00', '55.00', '0000-00-00 00:00:00', '2012-02-18 22:20:53');


CREATE TABLE IF NOT EXISTS `orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `company_id` int(11) NOT NULL,
  `total_cost` decimal(6,2) NOT NULL,
  `order_date` datetime NOT NULL,
  `status_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;


INSERT INTO `orders` (`id`, `user_id`, `company_id`, `total_cost`, `order_date`, `status_id`) VALUES
(1, 5, 2, '25.00', '2012-02-03 23:30:24', 1),
(2, 7, 2, '30.00', '2012-02-13 18:06:12', 1);


CREATE TABLE IF NOT EXISTS `orders_products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `order_id` int(11) NOT NULL,
  `product_id` int(11) NOT NULL,
  `product_name` varchar(100) NOT NULL,
  `cost` decimal(6,2) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;

INSERT INTO `orders_products` (`id`, `order_id`, `product_id`, `product_name`, `cost`) VALUES
(1, 1, 34, 'Chair', '10.00'),
(2, 1, 25, 'TV', '10.00'),
(3, 1, 27, 'Desk', '2.50'),
(4, 1, 36, 'Laptop', '2.50'),
(5, 2, 75, 'PHP Book', '25.00'),
(6, 2, 74, 'MySQL Book', '5.00');

อย่าลังเลที่คุณต้องการอัปเดต / เพิ่มตารางในตอบที่นี่

ขอบคุณ

คำตอบ:


8

การจับคู่เงินสด

นี่เป็นปัญหาการจับคู่เงินสด คุณสามารถติดตามได้ที่หนึ่งในสองระดับ:

  • เปรียบเทียบใบแจ้งหนี้กับตัวเลขเงินสด (ค่อนข้างเลอะเทอะ แต่นี่เป็นวิธีการทำธุรกิจภายในโดยองค์กรส่วนใหญ่ของ Lloyd ซึ่งมักเรียกว่ารายงาน 'เขียนเปรียบเทียบกับที่ลงนาม')

  • รักษาการจัดสรรเงินสดอย่างชัดเจนจากการชำระเงินสดแยกตามใบกำกับสินค้า

จากคำถามของคุณฉันคิดว่าคุณต้องการที่จะทำหลัง

โดยทั่วไปจะทำโดยมีชุดธุรกรรมเงินสดแยกต่างหากและตารางเชื่อมโยงที่มีการจัดสรรการชำระเงินสดให้กับใบแจ้งหนี้ ถ้าค่าเท่ากันหรือการจ่ายเงินสดมาพร้อมกับการอ้างอิงใบแจ้งหนี้เดียวคุณสามารถทำการจัดสรรโดยอัตโนมัติ หากมีความสัมพันธ์ M: M ระหว่างใบแจ้งหนี้และการชำระเงินคุณจะต้องทำกระบวนการจับคู่ด้วยตนเอง (การทำเช่นนี้โดยอัตโนมัติจะแตกต่างจากปัญหาเป้หลัง )

ระบบจับคู่เงินสดพื้นฐาน

ลองนึกภาพว่าคุณมีตารางใบแจ้งหนี้ตารางการชำระเงินสดและตารางการจัดสรร เมื่อคุณออกใบแจ้งหนี้คุณจะต้องตั้งค่าระเบียนใบแจ้งหนี้ในตารางใบแจ้งหนี้และบันทึก 'ลูกหนี้' หรือ 'เจ้าหนี้' ในตารางการจัดสรร

  • ใบแจ้งหนี้ # 1, $ 100

  • การจัดสรร: บันทึกที่มีการอ้างอิงถึงใบแจ้งหนี้ # 1 ประเภทธุรกรรม 'ลูกหนี้' และ $ 100 เนื่องจาก ไม่มีการอ้างอิงถึงการจ่ายเงินสดในบันทึกนี้

ตอนนี้คุณจะได้รับเงินสด $ 100

  • การจ่ายเงินสด (chq # 12345): $ 100

  • การจัดสรร: บันทึกที่มีการอ้างอิงถึงใบแจ้งหนี้ # 1 และ chq # 12345 ประเภทธุรกรรม 'เงินสด' และ -100 เนื่องจาก (จ่าย $ 100)

คุณสามารถพูดคุยเรื่องนี้กับความสัมพันธ์ M: M ที่คุณได้รับการชำระเงินหลายครั้งจากใบแจ้งหนี้เดียวหรือการชำระเงินที่ครอบคลุมใบแจ้งหนี้หลายใบ โครงสร้างนี้ทำให้การสร้างรายงานการควบคุมเครดิตเป็นเรื่องง่าย รายงานเพียงต้องการค้นหาใบแจ้งหนี้ที่มีอายุมากกว่า (พูด) 180 วันที่ยังมียอดคงค้าง

ต่อไปนี้เป็นตัวอย่างของสคีมาบวกสองสถานการณ์และการค้นหาตราสารหนี้ที่มีอายุมากขึ้น น่าเสียดายที่ฉันไม่มีอินสแตนซ์ mysql ที่ใช้งานได้ดังนั้นอันนี้สำหรับ SQL Server

-- ==============================================================
-- === CashMatch.sql ============================================
-- ==============================================================
--


-- === Invoices =================================================
--
create table Invoice (
       InvoiceID        int identity (1,1) not null
      ,InvoiceRef       varchar (20)
      ,Amount           money
      ,InvoiceDate      datetime
)
go

alter table Invoice
  add constraint PK_Invoice 
      primary key nonclustered (InvoiceID)
go


-- === Cash Payments ============================================
--
create table CashPayment (
       CashPaymentID    int identity (1,1) not null
      ,CashPaymentRef   varchar (20)
      ,Amount           money
      ,PaidDate         datetime
)
go

alter table CashPayment
  add constraint PK_CashPayment
      primary key nonclustered (CashPaymentID)
go




-- === Allocations ==============================================
--
create table Allocation (
       AllocationID       int identity (1,1) not null
      ,CashPaymentID      int  -- Note that some records are not
      ,InvoiceID          int  -- on one side.
      ,AllocatedAmount    money
      ,AllocationType     varchar (20)
      ,TransactionDate    datetime
)
go

alter table Allocation
  add constraint PK_Allocation
      primary key nonclustered (AllocationID)
go


-- ==============================================================
-- === Scenarios ================================================
-- ==============================================================
--
declare @Invoice1ID int
       ,@Invoice2ID int
       ,@PaymentID int


-- === Raise a new invoice ======================================
--
insert Invoice (InvoiceRef, Amount, InvoiceDate)
values ('001', 100, '2012-01-01')

set @Invoice1ID = @@identity

insert Allocation (
       InvoiceID
      ,AllocatedAmount
      ,TransactionDate
      ,AllocationType
) values (@Invoice1ID, 100, '2012-01-01', 'receivable')


-- === Receive a payment ========================================
--
insert CashPayment (CashPaymentRef, Amount, PaidDate)
values ('12345', 100, getdate())

set @PaymentID = @@identity

insert Allocation (
       InvoiceID
      ,CashPaymentID
      ,AllocatedAmount
      ,TransactionDate
      ,AllocationType
) values (@Invoice1ID, @PaymentID, -100, getdate(), 'paid')



-- === Raise two invoices =======================================
--
insert Invoice (InvoiceRef, Amount, InvoiceDate)
values ('002', 75, '2012-01-01')

set @Invoice1ID = @@identity

insert Allocation (
       InvoiceID
      ,AllocatedAmount
      ,TransactionDate
      ,AllocationType
) values (@Invoice1ID, 75, '2012-01-01', 'receivable')


insert Invoice (InvoiceRef, Amount, InvoiceDate)
values ('003', 75, '2012-01-01')

set @Invoice2ID = @@identity

insert Allocation (
       InvoiceID
      ,AllocatedAmount
      ,TransactionDate
      ,AllocationType
) values (@Invoice2ID, 75, '2012-01-01', 'receivable')


-- === Receive a payment ========================================
-- The payment covers one invoice in full and part of the other.
--
insert CashPayment (CashPaymentRef, Amount, PaidDate)
values ('23456', 120, getdate()) 

set @PaymentID = @@identity

insert Allocation (
       InvoiceID
      ,CashPaymentID
      ,AllocatedAmount
      ,TransactionDate
      ,AllocationType
) values (@Invoice1ID, @PaymentID, -75, getdate(), 'paid')

insert Allocation (
       InvoiceID
      ,CashPaymentID
      ,AllocatedAmount
      ,TransactionDate
      ,AllocationType
) values (@Invoice2ID, @PaymentID, -45, getdate(), 'paid')



-- === Aged debt report ========================================
--
select i.InvoiceRef
      ,sum (a.AllocatedAmount)                 as Owing
      ,datediff (dd, i.InvoiceDate, getdate()) as Age
  from Invoice i
  join Allocation a
    on a.InvoiceID = i.InvoiceID
 group by i.InvoiceRef
         ,datediff (dd, i.InvoiceDate, getdate())
having sum (a.AllocatedAmount) > 0

Mine มีตารางแยกต่างหากสำหรับใบแจ้งหนี้และการชำระเงิน คุณสามารถใช้ตารางร่วมกับการเชื่อมโยงภายใน การจับคู่เงินสดมักจะใช้วิธีการดังกล่าวในระบบบัญชี
ConcoutedOfTunbridgeWells

ฉันจัดการเพื่อแปลตัวอย่าง SQL Server ของคุณเป็น MySQL ฉันผ่านไปแล้วและฉันก็เข้าใจเป็นอย่างดีในตอนนี้ สิ่งที่จะAllocationTypeจะเป็นถ้าผมต้องการที่จะส่งเงินของลูกค้า? ฉันจำเป็นต้องแทรกลงในCashPaymentตารางด้วยหรือไม่ (ให้บอกว่าจ่ายเงินผ่าน BACS) หรือไม่
ฉันจะกลับมา

1
ใช่คุณต้องการบันทึกการชำระเงินสดสำหรับการชำระเงินทั้งขาเข้าและขาออก ประเภทธุรกรรมจริงสำหรับธุรกรรมจับคู่เงินสดนั้นขึ้นอยู่กับคุณ
ConcOfOfTunbridgeWells

1
คุณสามารถจับคู่ธุรกรรมจากใบแจ้งหนี้ทั้งสองทิศทางเทียบกับการชำระเงินแบบชำระครั้งเดียวหากคุณต้องการ ตัวอย่างเช่น: ใบแจ้งหนี้ขาออกราคา $ 100, ใบแจ้งหนี้ขาเข้าราคา $ 50 (-50) และยอดดุลการชำระเงินขาเข้าราคา $ 50 ที่ตรงกับใบแจ้งหนี้ทั้งสอง
ConcOfOfTunbridgeWells
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.