Generazione di fatture e tracciamento


11

Ogni 2 settimane, il sistema genererà le fatture per le aziende.

La società riceverà una fattura il 1 ° e il 16 ° ogni mese. (Verrà eseguito tramite Cron Job ogni 2 settimane. Scansionerà la tabella degli ordini e quindi si aggiungerà alla tabella 'fattura'. Esistono alternative?)

C'è un elenco di ordini dei clienti nella orderstabella e indica anche a quale società appartiene ( orders.company_id)

La invoicetabella calcola il costo totale degli ordini dalla orderstabella.

Sto cercando di capire come progettare un monitoraggio delle fatture ragionevole. A volte la compagnia dovrà inviarmi le tasse o a volte le invierò le tasse ( invoice.amount)

Devo tenere traccia delle fatture con quanto segue:

  • quando la società mi ha inviato l'importo
  • quando ho inviato l'importo alla società
  • quanto importo è stato ricevuto dalla società
  • quanto importo ho inviato alla società
  • ho ricevuto l'intero importo (in caso contrario, cosa devo aggiornare sul Db?)
  • stato della fattura (fattura inviata, annullata, importo ricevuto, importo inviato)

Ecco la progettazione del database che ho ideato:

tavolo aziendale

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

I clienti possono selezionare un'azienda dal mio sito Web.

tabella degli ordini

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 |
+----+---------+------------+------------+---------------------+-----------+

due clienti hanno ordinato i prodotti dall'azienda B ( orders.company_id = 2). So che i campi degli ordini non sono sufficienti, sono solo semplificati per te.

tabella ordini_prodotti

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 |
+----+----------+------------+--------------+-------+

Elenco dei prodotti che i clienti hanno ordinato.

tabella delle fatture

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 |
+----+------------+------------+---------------------+--------+-----------+

È qui che sono piuttosto bloccato sul design delle tabelle delle fatture. Non sono sicuro di come dovrebbe essere fatto. Le fatture verranno generate ogni 2 settimane. Dall'esempio di risultato invoice.amountè 55,00 perché è stato calcolato dalla orders.company_id = 2tabella

Se invoice.amountè -50,00 (meno), significa che la società dovrà inviarmi l'importo delle commissioni.

Se invoice.amountè di 50,00, significa che devo inviare alla compagnia le commissioni.

Lo status_id potrebbe essere: (1) Fattura inviata, (2) Annullato, (3) Completato

Devo aggiungere un invoice_idcampo nella orderstabella? Aggiorna il orders.invoice_idcampo quando la riga è stata inserita nella tabella 'fattura'.

tabella invoice_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 |
+----+------------+-----------------+-------------+---------------------+---------------------+

Qui è dove posso monitorare e aggiornare la transazione .. il pagamento verrà effettuato tramite BACS.

È un buon design da tavolo o cosa devo migliorare? Quali campi e tabelle dovrei aggiungere?

Se la fattura è stata generata e successivamente devo apportare le modifiche orders_productso le orderstabelle, dovrebbe ricalcolare il invoice.amountcampo? (Userò PHP / MySQL).

Dump SQL :

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');

Sentiti libero di voler aggiornare / aggiungere tabelle per rispondere qui.

Grazie

Risposte:


8

Incontro in contanti

Questo è un problema di abbinamento contanti. Puoi monitorare questo a uno dei due livelli:

  • Confronta i dati fatturati con quelli in contanti (un po 'sciatti ma in realtà è così che viene fatto per gli affari interni dalla maggior parte dei Sindacati di Lloyd, spesso chiamati un rapporto "scritto contro firmato").

  • Mantenere le allocazioni di contanti esplicite dai pagamenti in contanti suddivisi per fattura.

Dalla tua domanda penso che tu voglia fare quest'ultima.

In genere questo viene fatto disponendo di un insieme separato di transazioni in contanti e di una tabella ponte che prevede l'assegnazione dei pagamenti in contanti alle fatture. Se i valori sono uguali o il pagamento in contanti viene fornito con un unico riferimento di fattura, è possibile eseguire l'allocazione automaticamente. Se esiste una relazione M: M tra fatture e pagamenti, dovrai eseguire un processo di abbinamento manuale (farlo automaticamente è in realtà una variante del problema dello zaino ).

Un sistema di abbinamento di cassa di base

Immagina di avere una tabella delle fatture, una tabella dei pagamenti in contanti e una tabella di allocazione. Quando si emette una fattura, si imposta un record di fattura nella tabella delle fatture e un record di "credito" o "pagabile" nella tabella delle allocazioni.

  • Fattura n. 1, $ 100

  • Allocazione: un record con un riferimento alla fattura n. 1, tipo di transazione "ricevibile" e $ 100 dovuti. Nessun riferimento a un pagamento in contanti su questo record.

Ora ricevi un pagamento in contanti di $ 100

  • Pagamenti in contanti (chq # 12345): $ 100

  • Allocazione: un record con riferimento alla fattura n. 1 e chq n. 12345, tipo di transazione "in contanti" e -100 dovuti ($ 100 pagati).

È possibile generalizzare ciò in una relazione M: M in cui si ottengono più pagamenti per una singola fattura o un pagamento per più fatture. Questa struttura semplifica anche la creazione di report sul controllo del credito. Il rapporto deve solo trovare fatture più vecchie di (diciamo) 180 giorni che hanno ancora saldi in sospeso.

Ecco un esempio dello schema più un paio di scenari e una query sul debito obsoleto. Sfortunatamente non ho un'istanza mysql in esecuzione a portata di mano, quindi questa è per 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

Il mio ha tabelle separate per fatture e pagamenti. È possibile utilizzare una tabella comune con collegamento interno. Il cash matching è spesso implementato in questo modo nei sistemi contabili.
ConcernedOfTunbridgeWells,

Sono riuscito a tradurre il tuo esempio di SQL Server in MySQL. Ho attraversato e ho capito molto bene ora. Cosa sarebbe AllocationTypese desidero inviare denaro al cliente? Devo inserire anche nella CashPaymenttabella (diciamo pagandoli tramite BACS)?
Tornerò il

1
Sì, desideri un record di pagamento in contanti sia per i pagamenti in entrata che per quelli in uscita. I tipi di transazione effettivi per le transazioni di abbinamento in contanti dipendono da te.
ConcernedOfTunbridgeWells,

1
Se lo desideri, puoi abbinare le transazioni delle fatture in entrambe le direzioni con un unico pagamento. Ad esempio: fattura in uscita per $ 100, fattura in entrata per $ 50 (-50) e pagamento in pareggio in entrata per $ 50 corrispondenti a entrambe le fatture.
ConcernedOfTunbridgeWells,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.