1

Please bear with me if the question looks not well structured.

To put you in the context of my issue:

I am building an application that invoices vehicles stay duration in a parking. In addition to the stay service there are some other services. Each service has its own calculation logic.

Here is an illustration (please correct me if the design is wrong):

public abstract class Service
{
   public int Id { get; set; }
   public bool IsActivated { get; set; }
   public string Name { get; set }
   public decimal Price { get; set; }
}

public class VehicleService : Service
{   
   //MTM : many to many
   public virtual ICollection<MTMVehicleService> Vehicles { get; set; }
}

public class StayService : VehicleService
{

}

public class Vehicle
{
   public int Id { get; set; }
   public string ChassisNumber { get; set; }
   public DateTime? EntryDate { get; set; }
   public DateTime? DeliveryDate { get; set; }
   //...
   public virtual ICollection<MTMVehicleService> Services{ get; set; }
}

Now, I am focusing on the stay service as an example:
I would like to know at invoicing time which class(es) would be responsible for generating the invoice item for the service and for each vehicle? This should calculate the duration cost knowing that the duration could be invoiced partially so the rule is as follows: not yet invoiced stay days * stay price per day.

At this moment I have InvoiceItemsGenerator do everything but I am aware that there is a better design.

  • Not sure what MTMVehicleService is for. A service can have a collection of vehicles and a vehicle can have a collection of services. We will need to see something of InvoiceItemsGenerator before it is possible to comment on your traversal algorithm. What is the better design you are aware of? – Mr Cochese May 30 '14 at 23:08
  • Yes, in other words, we can have many services, each service has a related to collections of vehicles. for ex: "Customs check" customs come and check 1 to many vehicles in date1, and other vehicles in date2 etc – HichemSeeSharp May 30 '14 at 23:14
  • 1
    For the design, I just want to get each class of these its own piece of business logic so I get rid of InvoiceItemsGenerator that contains "traversal algorithm" – HichemSeeSharp May 30 '14 at 23:37
  • 1
    the items generator...explicitly - that's the problem, as you know. Maybe try weeding through that business logic and breaking it out into discreet classes that represent the different sorts of logic and apply it -perhaps a class hierarchy with a factory method-can be used by the invoice generator and other classes as well. Rules engine is buzzword one of my old bosses liked - sort of a pipeline - send your request down a "dark tunnel" that knows what to do with it... not really much different when you get down to it. A regular class hierarchy should work. – Vector May 31 '14 at 1:12
  • 1
    One question that you can ask yourself is: let's say InvoiceItemsGenerator has been broken up into pieces. For each piece, what information does it need (values it need to retrieve from a database or read from another class) in order to do its work (generate the invoice item of its type)? Use this visibility/need to help break up the class. If every invoice item needs full visibility to every piece of information (e.g. to apply discounts), maybe only a rules engine or even raw database queries (read-only) would satisfy. – rwong May 31 '14 at 13:23
1

I would like to know at invoicing time which class(es) would be responsible for generating the invoice item for the service and for each vehicle?

It seems pretty obvious that would be the responsibility of your InvoiceItemsGenerator class.

Your problem is with your implementation of InvoiceItemsGenerator, which you say contains bundled within it all the business logic for the various sorts of business and their corresponding invoices, etc.

Maybe try weeding through that business logic and breaking it out into discreet classes that represent the different sorts of logic and apply it -perhaps a class hierarchy with a factory method- it can be used by the InvoiceItemsGeneratorand with further refactoring, perhaps by other classes as well.

Grossly oversimplified and not compilable:

class BaseServiceInvoiceProcessor
{
  Invoice generateInvoice(){...}
};

class VehicleServiceInvoiceProcessor:BaseServiceInvoiceProcessor{...}
class StayServiceInvoiceProcessor:BaseServiceInvoiceProcessor{...}

BaseServiceInvoiceProcessor getInvoiceProcessor(enumServiceTypes serviceType){...}

InvoiceItemsGenerator
  {
    ...
   Invoice GetInvoiceByServiceType(enumServiceTypes serviceType)
    {
       BaseServiceInvoiceProcessor iProc= getInvoiceProcessor(serviceType);
       return iProc.generateInvoice()
    } 

   };    

etc.

  • I understand that using InvoiceItemsGenerator class is not a bad practice. Because I thought it's somehow preferable to embed business logic in the model classes (from MVVM practices). – HichemSeeSharp May 31 '14 at 22:16
  • @HichemSeeSharp - (repeated this because of typo..) MVVM says separate business logic from the presentation. That doesn't mean you bundle all your business logic together in one place. I do very little GUI work - mostly server side - my code is highly modularized. "Bundling" at any level is bad: makes your code difficult to manage, highly prone to breakage, difficult to test.... THINK LEGO. – Vector Jun 2 '14 at 4:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.