Génération de factures et suivi

11

Toutes les 2 semaines, le système génère les factures des entreprises.

L'entreprise recevra une facture le 1er et le 16 de chaque mois. (Il s'exécutera via Cron Job toutes les 2 semaines. Il parcourra le tableau des commandes, puis s'ajoutera au tableau des «factures». Y a-t-il une alternative?)

Il y a une liste de commandes clients dans le orderstableau et il indique également à quelle entreprise il appartient ( orders.company_id)

Le invoicetableau calcule le coût total des commandes à partir du orderstableau.

J'essaie de comprendre comment concevoir un suivi raisonnable des factures. Parfois, l'entreprise devra m'envoyer les frais ou parfois je leur enverrai les frais ( invoice.amount)

J'ai besoin de suivre les factures avec les éléments suivants:

  • lorsque l'entreprise m'a envoyé le montant
  • quand ai-je envoyé le montant à l'entreprise
  • le montant reçu de l'entreprise
  • combien ai-je envoyé à l'entreprise
  • ai-je reçu le montant total (sinon, de quoi ai-je besoin pour mettre à jour le Db?)
  • état de la facture (facture envoyée, annulée, montant reçu, montant envoyé)

Voici la conception de la base de données que j'ai élaborée:

table entreprise

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

Les clients peuvent sélectionner une entreprise sur mon site Web.

tableau des commandes

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

deux clients ont commandé les produits à la société B ( orders.company_id = 2). Je sais que les champs de commandes ne suffisent pas, simplement simplifiés pour vous.

Table commandes_produits

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

Liste des produits que les clients ont commandés.

table de facturation

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

C'est là que je suis assez coincé sur la conception des tableaux de facturation. Je ne sais pas comment procéder. Les factures seront générées toutes les 2 semaines. De l'exemple de résultat invoice.amountest 55,00 car il a été calculé à partir du orders.company_id = 2tableau

Si la valeur invoice.amountest -50,00 (moins), cela signifie que la société devra m'envoyer le montant des frais.

Si la valeur invoice.amountest de 50,00, cela signifie que je dois envoyer les frais à l'entreprise.

Le status_id peut être: (1) Facture envoyée, (2) Annulée, (3) Terminée

Dois-je ajouter un invoice_idchamp dans la orderstable? Mettez à jour le orders.invoice_idchamp lorsque la ligne a été insérée dans le tableau "facture".

table de facturation_paiement

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

C'est là que je peux suivre et mettre à jour la transaction .. le paiement sera effectué via BACS.

Est-ce une bonne conception des tables ou que dois-je améliorer? Quels champs et tables dois-je ajouter?

Si la facture a été générée et que je dois par la suite apporter les modifications dans orders_productsou les orderstableaux - doit-elle recalculer le invoice.amountchamp? (J'utiliserai 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');

N'hésitez pas à mettre à jour / ajouter des tableaux pour répondre ici.

Merci

Je reviendrai
la source

Réponses:

8

Appariement en espèces

Il s'agit d'un problème de contrepartie en espèces. Vous pouvez suivre cela à l'un des deux niveaux:

  • Comparez les chiffres facturés aux espèces (quelque peu bâclés, mais c'est en fait ainsi que la plupart des syndicats de Lloyd's procèdent pour les affaires entrantes, souvent appelé un rapport écrit ou signé).

  • Maintenir des allocations de trésorerie explicites à partir des paiements en espèces, ventilés par facture.

D'après votre question, je pense que vous voulez faire ce dernier.

En règle générale, cela se fait en ayant un ensemble distinct de transactions en espèces et une table de transition qui répartit les paiements en espèces sur les factures. Si les valeurs sont égales ou si le paiement en espèces est accompagné d'une seule référence de facture, vous pouvez effectuer la répartition automatiquement. S'il existe une relation M: M entre les factures et les paiements, vous devrez effectuer un processus d'appariement manuel (le faire automatiquement est en fait une variante du problème du sac à dos ).

Un système de base de contrepartie en espèces

Imaginez que vous ayez une table de facturation, une table de paiements en espèces et une table de répartition. Lorsque vous émettez une facture, vous configurez un enregistrement de facture dans le tableau des factures et un enregistrement «à recevoir» ou «à payer» dans le tableau des répartitions.

  • Facture # 1, 100 $

  • Affectation: un enregistrement avec une référence à la facture n ° 1, le type de transaction «à recevoir» et 100 $ dus. Aucune référence à un paiement en espèces sur cet enregistrement.

Maintenant, vous obtenez un paiement en espèces de 100 $

  • Paiements en espèces (chq # 12345): 100 $

  • Affectation: un enregistrement avec une référence à la facture # 1 et au chq # 12345, type de transaction «en espèces» et -100 dû (100 $ payés).

Vous pouvez généraliser cela à une relation M: M où vous obtenez plusieurs paiements sur une seule facture ou un paiement couvrant plusieurs factures. Cette structure facilite également la création de rapports de contrôle de crédit. Le rapport a juste besoin de trouver des factures de plus de (disons) 180 jours qui ont encore des soldes impayés.

Voici un exemple du schéma plus quelques scénarios et une requête de dette ancienne. Malheureusement, je n'ai pas d'instance mysql en cours d'exécution à portée de main, donc celle-ci est pour 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
ConcernedOfTunbridgeWells
la source
Le mien a des tableaux séparés pour les factures et les paiements. Vous pouvez utiliser une table commune avec liaison interne. L'appariement des espèces est souvent mis en œuvre de cette façon dans les systèmes comptables.
ConcernedOfTunbridgeWells
J'ai réussi à traduire votre exemple SQL Server en MySQL. J'ai traversé et j'ai très bien compris maintenant. Que serait- AllocationTypece si je voulais envoyer de l'argent au client? Dois-je également insérer dans le CashPaymenttableau (disons les payer via BACS)?
Je serai de retour le
1
Oui, vous souhaitez un enregistrement des paiements en espèces pour les paiements entrants et sortants. Les types de transaction réels pour les transactions de rapprochement de trésorerie vous appartiennent.
ConcernedOfTunbridgeWells
1
Si vous le souhaitez, vous pouvez faire correspondre les transactions des factures dans les deux sens avec un seul règlement. Par exemple: facture sortante de 100 $, facture entrante de 50 $ (-50) et solde des paiements entrants de 50 $ comparés aux deux factures.
ConcernedOfTunbridgeWells