I have a system that creates an order and that order can be billed to a house account, sent Cash on Delivery (COD), or charged to a credit card. I\'ve created the following
You can do it either way: a big honking billingoptions
table that has fields that encompasses all of the types, with NULLs for fields that don't apply to a given type, or a bunch of baby tables that "star off" of a parent billingoptions
table. Both have their advantages and disadvantages.
For the big honking table,
For the small baby tables,
At work, we ended up going with small baby tables. It looks something like this:
Table Orders: --> OrderId PK --> (Lots of Other Fields) Table Payments: --> PaymentId PK --> OrderId (FK) [There may be more than one payment per order] --> PaymentType [Restricted field contains values like 'PAYPAL' or 'CREDIT', you use this to know which baby table to look up that can contain additional information] Table PaymentsPayPal: --> PaymentPayPalId PK --> PaymentId FK points to Table Payments --> TransactionNo --> (Other PayPal specific fields) Table PaymentsCheck: --> PaymentCheckId PK --> PaymentId FK points to Table Payments --> RoutingNo --> (Other e-check specific fields) + other tables for remaining payment types....
All of the payment types share three transaction related tables:
Table PaymentApprovals: --> PaymentApprovalId PK --> PaymentId FK points to Table Payments --> Status [Some flag meaning 'Succeeded', 'Failed', 'Reversed', etc] --> ProcessorMessage [Something the service sent back, like '(M) CVV2 Matched'] --> Amount --> (Other administrative fields) Table PaymentDeposits: --> PaymentDepositId PK --> PaymentApprovalId FK points to Table PaymentApprovals --> Status --> ProcessorMessage --> Amount --> (Other administrative fields) Table PaymentRefunds: --> PaymentRefundId PK --> PaymentDepositId FK points to Table PaymentDeposits --> Status --> ProcessorMessage --> Amount --> (Other administrative fields)
All of our payment methods (Credit Card, PayPal, Google Checkout, Check, Cash, Store Credit, and Money Order) are abstracted to fit into this Approval --> Deposit --> Refund metaphor, and the UI calls the same methods on an IPayment
and IPaymentProcessor
interfaces with different implementations (CybersourcePaymentProcessor
, PayPalPaymentProcessor
, etc). The abstraction has worked pretty well over the past year and a half across these disparate methods, although sometimes the GUI will display different verbiage to the user (for example, it'll say "Authorize" and "Charge" instead of "Approve" and "Deposit" for credit card payments, and the screen for entering cash performs the Approve/Deposit step in one fell swoop.)
Hope that makes sense. It sounds like you're not actually storing payment information, but it's useful to think about where these things can end up.
Focus on things. Actual things. Try to describe things simply, directly, and in natural language first.
Then, when you ask for design guidance, you can provide definitions. In some cases, the act of writing definitions will make the design crystalize.
Orders are things. What are the attributes of an order? Customer, Product, Payment/Billing options.
Billing Options are (almost) things. You can, apparently, define and identify them. (I'm not sure I could. From your question, it appears that you might be able to. But without a one-sentence summary, I'm not sure what's going on with Billion Options.
What's a "billing data?" What kind of thing is this? What attributes (or properties) does it have?
How does a "Billing Data" relate to an Order? How does it relate to a Billing Option?
Feel free to update the question with definitions for each thing.