I would like to make report from sales data in a POS system.
So, I have a ReportGenerator that has a List <Ticket>
The Ticket class represents a registration in the cash register. This can be a SalesTicket (DirectSalesTicket, InvoiceSalesTicket,...) or CashRegisterMovementTicket for a registration of money leaving or entering the cash register without a sale (e.g. taking money to the bank).
InvoiceSalesTicket has a invoiceNumber which a DirectSalesTicketdoesn't have. So I'm OK with having 2 different classes.
For CashRegisterMovementTicket I could make 2 classes (CashInRegisterMovementTicket and CashOutRegisterMovementTicket) that inherent from CashRegisterMovementTicket(which is a Ticket) that represent money that was added to the cash register or money that was taken out of the register.
That would make 3 classes, that do not really differ from one another internally.
When I want to generate a report with al the money that has been taken out of the cash register I can just take the List <Ticket> and only use the ones that are of the CashOutRegisterMovementTicket type.
Another example:
SalesTicket has List <SalesLine>
Some reports are based on SalesTicket that have a gift certificate
So I have NormalSalesLine and GiftCertificateSalesLine, both inherent from SalesLine but internally they are the same.
It feels like I have a lot of classes that are sometimes very similar.
What am I missing?
I think your approach is fine, however if you had only a SalesTicket with a TransactionType property (Invoice, Direct Sales, Cash, etc.) then you can use that property in the report for display or filtering.
If you had some abstract method that is implemented differently across the various SalesTicket types (like CalculateTax()... ) then you had a good reason for multiple types.
Related
I was reading about DDD and I realize that sometimes an entity might be a VO or VO might be an entity. You can know which one is better depends on the context. I was checking different examples. For example, shopping cart DDD example. Product is an aggregate root, Cart is an aggregate root and items is a entity of Cart, so if you want to add a product to the cart you would do something like this:
$cart->addProduct(id $id, $name, $price)
class Cart
{
private items;
function addProduct(ProductId $id, ProductName $name, ProductPrice $price) {
this->items[] = new Item(
new ItemProductId($id->ToString()),
new ItemName($name->ToString()),
new ItemPrice($price->ToString()),
new ItemCartId(this->id->ToString())
);
}
}
There are two reasons why I think it is a VO:
You cannot modify the value's item ( only if the product's
price has been modify there is a event that would modify its price).
The item doesn't have id, it's has a reference of the
product(ItemProductId) and a reference of the cart (ItemCartId)
I was reading about DDD and I realize that sometimes an entity might be a VO or VO might be an entity. You can know which one is better depends on the context.
Usually its pretty clear whats entity and whats an value object. If it contains data that's fixed at the time of assignation, its a value object. For example "order address" on the order aggregate. When the order is placed, the address is set. "Addresses" may be an entity in user aggregate (i.e. a list of his common addresses), but for an order its an value object since its not supposed to change when the user edits or deletes one of his addresses.
cart->addProduct(id $id, $name, $price)
class Cart
{
private items;
function addProduct(ProductId $id, ProductName $name, ProductPrice $price) {
this->items[] = new Item(
new ItemProductId($id->ToString()),
new ItemName($name->ToString()),
new ItemPrice($price->ToString()),
new ItemCartId(this->id->ToString())
);
}
}
That's a pretty bad example. Why would or should the value object be ItemPrice? Does that makes it any special? Why string? A price is usually just a numeric value but also involves a currency, passing it as string kinda beats that.
On top of that, having ItemCartId in the it does
a) leak data persistence knowledge into your domain. The fact, it's contained inside this->items[] already establishes a relationship between the entity (or aggregate) and the value object. ItemCartId as no meaning in the domain, other than that it's required for relational database engines (=persistence knowledge)
There are two reasons why I think it is a VO:
You cannot modify the value's item ( only if the product's price has been modify there is a event that would modify its price).
You sure? Why would a eCommerce business want to have the prices in the card anyways?
Prices are informational only, they could change before the order is placed. Same as availability.
A lot of users put stuff in their cart and check on next day. In that time, the price could change.
No company would want to sell a product for the price when it was put into the shopping cart, if the price increased in the time since it was put in there. That would mean a financial loss.
Prices in the shopping carts are informational, not compulsory. You need know the exact process of the company.
The item doesn't have id, it's has a reference of the product(ItemProductId) and a reference of the cart (ItemCartId)
Again. Why do you think ItemCartId belongs to the Item object? That's leaked persistence knowledge, since its only important for relational database systems.
All you really need in a shopping cart is
* product or article number (not necessary the id, that's typically db knowledge)
* quantity
Nothing else. If you may want to change the user when the price changed and show the old and new price, the take the price (=currency value object, not ItemPrice) to it too as a value to compare to an old state.
Finally and probably most importantly: Consider if the shopping cart is an aggregate at all (or does fit into ddd).
After all, most shopping carts are only a value bag w/o a lot of business logic into it. The real logic (checking the real price, product availability, asking for shipping location, calculation of taxes and shipping costs) happens during the checkout process, not while putting stuff into the cart.
For example you can check out eShops on Containers demo project showing an example shopping service based on microservices and ddd.
Some microservices apply DDD (such as Ordering microservice), where others don't (Catalog microservice or the Basket (cart) Microservice).
Applying DDD doesn't mean everything needs to be done with DDD. If its simple crud based services, then you don't need DDD for these. DDD adds a value where you have complex systems and complex business logic.
A catalog has neither, it just presents data which come from a different system (i.e. ERP which on other side may be built on using DDD).
I don't understand what are you asking exactly, but the code you are providing could be improved.
First of all I suggest you to read the red book by Vaughn Vernon https://www.amazon.co.uk/Implementing-Domain-Driven-Design-Vaughn-Vernon/dp/0321834577: you can find 3 chapters describing how to define entities, value objects and aggregates, with some rules of thumbs.
One of those advices, is to keep your aggregates as small as possible, in order to improve your performance and keep the code easy to read and maintain. Imagine that you have a Blog aggregate that contains a list of Post entities: if you manage all of them in a single aggregate, when you want to modify the blog Author, for example, you are forced to retrieve all of the blog's post, without any reason, and that means that you are doing a join and slowing down your application. The more your aggregates grows, the slower those queries with their joins.
So, in the case of the Cart, I suggest you to build the cart without any item or product, instead you can add the CartId to the Item. Cart does not know which items it contains, but items know in which cart they are.
About value objects: is a tool that allows you to wrap some validation and business logic inside a class that is represented by its state and not by its id (like entities), so in the case of the cart, if you put two identical bottles of water inside it, how can you know that they are different? Do you need to know that they are different? Are they different if they are physically (or logically different) or are they different if some of their attribute is different?
In my opinion an item or a product, in your case, are entities because they are not measuring anything, and when you put an item twice, you actually have two different items (and you use an id to recognize them).
This is not necessary like this, sometime you can use a value object and sometimes an entity, it depends on your context. A good example to understand that difference is with money:
if you want to measure an amount, for example 10 dollars, probably a value object will work for you, because you don't care if it a bill or another, you just want to measure 10 dollars; in this case if you have 10 dollars, is not important if you have a bill or another, the important thing is that is 10 and not 5
in the case that you need to recognize different physical bills, for any reason (you need to track money for the police), you should use an entity, because any printed bill has a unique serial number, and a 10 dollar bill, in this context, is actually different from another 10 dollar bill
Hope this can help you.
Goodbye!
Let us assume there is a situation when I have an invoice from a supplier to my company (e.g. 1000 EUR). My company returns all the goods because of a problem. The supplier shall issue a credit invoice in amount of 1000 EUR, which I register in my system. As a result I will have (on behalf of the supplier) an account payable of 1000 EUR and an account receivable in the same amount. What is the preferred way of handling this situation, because there will be no money transferred, either way.
Should I generate a paymentApplication to both invoices? I want to see them as +1000 -1000 = 0 EUR.
The current data model and services do not support applying an invoice to an invoice, i.e. canceling part or all of one invoice with another. That is something I have considered but IMO is messy... even if it is a common practice in certain parts of the world (from my limited knowledge of it an archaic practice that isn't so commonly used any more). That could be supported though, I have certainly considered it (adding an entity or perhaps modifying PaymentApplication to support it, adding a service to do it and a corresponding GL posting service to balance AP/AR accounts).
Right now the best thing to do a cancel the original invoice, which does the proper reverse GL postings if the invoice has already been posted.
If you want both invoices in the system and canceling entries somewhere the currently supported approach is to use a FinancialAccount, basically use FinancialAccount payments to pay both invoices and then the balance of the FinancialAccount represents the amount due or owed to the external party. There is full support for these sorts of FinancialAccount transactions, doing payments both ways (withdrawals and deposits), representing the liability for positive balances in the GL, etc.
When using API calls such as https://developer.yodlee.com/Indy_FinApp/Aggregation_Services_Guide/REST_API_Reference/getItemSummaries to get item summaries, is there any guarantee of consistency of fields between different institutions for the same acctType?
As an example, if you have a savings account (i.e. acctType is savings) with Westpac (Australian Institution) which has a currentBalance with amount 368.00 and currency AUD, will the same field currentBalance exist for a savings acctType for ANZ (another Australian institution), with the exact same fields. Is there a comprehensive list which details which fields differ across acctType (should they differ at all)?
Furthermore, is there an enumeration of the possible acctType that you can get when querying customer data from an institution
Also is there documentation that describes what field names mean, as an example there is acctType and localizedAcctType, what is the difference between the two?
Finally is there a list of institutions separated by countries (in my case, Australia) that we can use by reference?
Yodlee has data model designed as per different types of banking products like bank accounts, credit card accounts, loan accounts, investment accounts and so on. In Yodlee's terminology all these different products are called as containers. Now each container has their own set of fields which are relevent to any type of accounts under that category. Account_types are also a field under each container.
Now savings/Checking accounts comes under bank container and will have same set of fields across all financial institutions and will not vary until and unless the financial institution does not have any of those fields present at their website.
You can find the list of accountTypes from this link
https://developer.yodlee.com/Indy_FinApp/Aggregation_Services_Guide/Data_Model/Yodlee_Account_Types
For complete look at the Yodlee data model you can check
https://developer.yodlee.com/Indy_FinApp/Aggregation_Services_Guide/Data_Model
As of now we don't have any documentation which provides the meaning of each an every fields. You can actually ignore the localizedAcctType field and use the value from acctType field. Similarly you can ignore any such fields for different responses.
There is no such list available but there are APIs to get list of institutions by geographic region.
First off, I appreciate any help with this.
I am struggling to find the best approach to some database design, and I'm not entirely sure where even to start searching for the type of design I am even after.
In short, we have a bunch of payment method types, for example cash, credit card and paypal. But each of these methods require their own set of parameters both for their setup details (ie information for API details for PayPal) as well as transactions for each method requiring a different set of fields - ie. for credit card - we would want the start date, end date, card number etc.. - for paypal we would want the email address and a bunch of other stuff.
Now - I could simply have tables: payment_method_types, payment_methods and payments which have all the required fields to cover all bases - for example paypal_email_address field, etc.. but is there a better solution that mimics more of a document-based database whereby you'd just have the relevant fields?
For example the following tables payment_method_types, paypal_payment_methods, cash_payment_methods, paypal_payments, cash_payments etc.. Which doesn't really seem that nice.
There must be a good solution for what it is I want to achieve? Do I just need to include all possible fields (ie. paypal_email_address etc..) and just handle it within my application?
Thanks very much for any input.
I could be downvoted by that by relational guys :), but you can store this type of information in JSON (there's good support of JSON in PostgreSQL version 9.3) or hstore columns, it could be good mix of relational database and noSQL style.
You can store common fields like Amount, Date, Currency and so on in typed columns and have one column of type JSON/hstore to store additional details like card number. So your data could look like:
Type Date Amount Currency Additional
Credit Card 2013-08-01 15.1 EUR {Card Number: "XXXX-XXXX-XXXX-XXXX"}
PayPal 2013-07-02 103.8 USD {Email: "client#company.com"}
or hstore:
Type Date Amount Currency Additional
Credit Card 2013-08-01 15.1 EUR Card Number => "XXXX-XXXX-XXXX-XXXX"
PayPal 2013-07-02 103.8 USD Email => "client#company.com"
Or you can create subtables for additional information - so you store common data in table Payments and store all additional info in PaymentsPayPal, PaymentsCreditCard and so on.
This answer can be very complex, but I will go with something simple to inspire only. Something like
CreditCardPayment < ActiveRecord::Base
include PaymentType
def paypal_some_kind_of_id
2
end
end
PaypalPayment < ActiveRecord::Base
include PaymentType
def paypal_some_kind_of_id
1
end
end
Then, whenever dealing with payments, write only one method, and make sure the method works with both a PaypalPayment and a CreditCardPayment object. Methods that are equal for all classes can go within the PaymentType module, to keep your code dry.
We create point of sale software for the mac, and are looking to revamp our tax engine. It's pretty simple now, with taxes consisting of a name, code and rate that can be applied to every product individually. While this is good enough for some people, we've had lots of requests to handle more advanced situations. Some examples are US City/County sales tax, Canadian compound (stacked) taxes, French ecotax and NYC luxury tax.
We've identified most of the characteristics that these taxes have and are leaning towards a sort of rule-engine based implementation. We don't have to support every case out there, but we want to be able to extend it if needed (to avoid another rewrite).
We're looking for advise from people who built something like this before, or examples of projects that try to solve the same in an elegant way.
My suggestion would be to use database tables for what they are good for (storing values) and rules for what they are good for (business logic). I would certainly not put things like tax rates or lists of jurisdictions in rules - those should be in tables. What I would use a rules engine for is defining the logic that determines which rate to apply to which transactions. So, for instance, if I buy a set of products online from a company based in State X that ships from State Y to three different locations, what tax rates apply to which parts of the transaction?
This combination of rules and database tables is very common - the rules make sure you look up the right things while the tables aid in reporting etc. For instance, the California DMV did this with vehicle registration fees - all the various fees are stored in a database while the rules that determine which fee applies to which car are managed in a rulebase.
If you try and put everything in rules you will not be able to report well and if you try and put everything in database tables you will end up with dozens of tables to manage all the exceptions and corner cases.
JT
I would recommend a set of database tables and joins.
Example:
Jurisdiction: list of states, counties, countries, cities, etc.
Product: obvious
Store: list of locations you sell from
StoreJurisdiction(StoreID, JurisdictionID): the list of Jurisdictions the store is
responsible to collect taxes for
ProductTaxCode(ProductID int, TaxCodeID int): the type of product for the purposes of taxes: basic, luxury, etc.
JurisdictionTaxCodeRate(JurisdictionID, TaxCodeID, InterestRate, RateType): for each applicable combination of Jurisdiction and Tax Code, provide the tax rate to be applied, and the type of rate (compound, simple, etc.).
To find the list of taxes to apply, all you need is an INNER JOIN of the store, its jurisdictions, the jurisdictiontaxcoderates for those Jurisdictions, and the product's tax codes.
You could define ProductTaxCode as a View so all products receive a default TaxCode unless a special one is provided. By abstracting TaxCode, you can have the same metadata about a product ("Food" for instance) apply to different regions in different ways. If a particular jurisdiction has its own definition of "food", you just add a jurisdiction-specific code and apply it to products as needed.
This may require some tweaking for Internet purchases, wholesale purchases, and other situations where the sale is somehow exempt from taxes or the customer is responsible for remitting them. It would also need tweaking for situations where the customer's location, rather than the store, decides the tax rate.
Other tweaks: here in Texas, for instance, we have a "tax-free" weekend where state and local taxes are not collected on some classes of products where the individual item's sale price is less than $100. The idea is to provide cheaper school supplies, clothing, etc. for children heading off to school for a new year. This sort of tweak could be implemented by having a date range table for each JurisdictionTaxCodeRate going off in the future as far as they can be planned.
Here is an example of a "home rule" city in the Denver, CO metropolitan area:
http://www.c3gov.com/pages/about/division_salestax.html
You, as a retailer, may also need to send the tax payments to different locations. For cities that are not "home rule" cities (which is a special term that probably only applies to Colorado, but then probably every state has some equally special term like it), you'll send all the tax payments to the state who will then deal them out to the relevant parties. Colorado has a feature where there are "special tax districts" that are permitted to collect sales taxes for certain benefits (on the example link, RTD is the public transportation district, and "Invesco Field" is the stadium where the Denver Broncos play).
To expand upon Mr Tallent's answer on this thread, you'll need to also include in the Jurisdiction table some way of representing that the taxes may go to different places.