Jump to content

seebs

Members
  • Posts

    19
  • Joined

  • Last visited

seebs's Achievements

Newbie

Newbie (1/14)

5

Reputation

  1. So I'm trying to add a thing allowing discounts to be incorporated into services, line items, etcetera. A discount is a percentage discount multiplier, which is not a coupon or coupon code. It applies to a single specific line item, and it's a percentage multiplier that stays a distinct feature of the line, rather than being turned into a separate line item with a fixed dollar value. And I have this working for a lot of stuff, but services continue showing unmodified values. On study, it appears that services, and services alone (??), are using an entire new pricing infrastructure, Core/Pricing, which has things like UnitPrice and ItemPrice and so on. Concern #1: It doesn't appear universally true that a service's computed price total will match the computed price total for a generated invoice. Even without the new feature I added to invoices, there's simply no guarantee that the math will be identical. Invoices are, in current Blesta (without my patch) computing the sum in SQL, not in PHP, so there's no real control over the rounding, etc, going on. For items with many package items with sub-cent prices, or pro-ration, I could see this producing unexpected values. Concern #2: I am not very clear on how I'd have to modify this to add a different kind of discount, where the discount is a per-item value innate to the item, not associated with a coupon, but I really want to. But once you get into the coupons, and taxes, and so on, it worries me that so far as I can tell, there's two completely independent implementations of all the pricing logic now. Unless all the old stuff is deprecated and I failed to spot that in comments. But I know that my discount code which modifies invoices/services/etc. appears to work for everything else in the system, just not for the costs shown in service editing or service lists. So I'm guessing nothing else is using this yet.
  2. Okay, so, I found a couple of typos, and I've fixed those, and this is working for many things. But not for everything, because it turns out there's a fairly large and complicated set of things in vendors/blesta/pricing which do their own price computations, completely separate from, so far as I can tell, all the price computations used when processing actual invoices. So in a list of services, the field saying "1 month at $125" is generated through fairly complicated nested series of operations on ItemPriceCollections, ItemPrices, UnitPrices, and so on. And that even has hooks for a "DiscountPrice" functionality... But I don't see anything else talking to this. So, for instance, the total of line items for an invoice is just computed on the fly in SQL, and so far as I know, that's the total actually used for determining whether an invoice is valid. But the estimates for services use this entire different architecture, and I'm not sure how to get another data item into it, such as a flat discount percentage. And it looks like nothing is actually using that functionality yet (?). So now I'm really confused by what's even happening there. discount.patch
  3. This is NOT production-ready, but this is what I've got going so far. In particular: I don't really understand the db migration tasks, or how I would create a migration and hint for it to be run, so right now if you want to use this, you'll have to manually add discount fields to services, service_options, invoice_lines, and invoice_recur_lines. (In all cases, any-old-int type should be fine.) What this is supposed to do: Allow per-item discounting. This is distinct from coupons in a couple of ways. One is that the discount can be distinct for each package option in a package. Another is that the discount is actually preserved as a trait of the line item, rather than being computed statically and stored as a separate line item. So if something changes that would change the cost of a given line (pricing or quantity, for instance), the discount reflects that. I haven't fully tested this, I don't think I've gone through the recurring line item use case at all, and I haven't figured out all the GUI elements. I'd quite like to see this get merged into core, or something like it, and I'm aware that it'll need significant cleanup before that would be plausible. But I want to get it out there for people to look at. (I think @Tyson might be the person to look at something like this?) It's a patch, not a plugin, because plugins can't alter invoice pricing computations. discount.patch
  4. and a followup: got that working, by adding a parallel configdiscounts/config_discounts thing. With that in place, I've gotten a service to autorenew with appropriate discounts. I don't know if prorating is working correctly, I haven't actually tested recurring invoices, and I need to get the default invoice template to show the thing, but the functionality is now working.
  5. Okay, so, it's pretty easy to make this work for invoices themselves, and also pretty easy for recurring invoices. For services... It's a lot harder. The issue here is that a whole lot of stuff assumes that package configuration will have exactly one datum per possible option, so of course that is the value-or-quantity. And this means that the services code, and the package_options code, and the admin and client controllers, all rely on the assumption that you can have a single table of [option_id -> value] items that is everything you need to know about a package's configuration. So, what if I wanted a second item of data, which is what discount rate if any to apply to this option? Welp. And this is additionally complicated because I genuinely can't figure out the meaning of the "value" field in package_option_values. It gets used in some cases as a quantity, but only in some, but it looks as though a value set there would override values set explicitly elsewhere, maybe? So... I'm not sure what that's for. There's only one package_option_values entry for a given thing, even if there's several services configured which have that option and specify different amounts; that's the qty field of service_options. So... I don't get what "value" is for. (Maybe it makes more sense for non-quantities?) So it seems to me that probably the right choice is not to try to overload the config_options/configoptions channel, but I'm still a bit unclear on the relationships between the package_options model and the service_options stuff. It looks like editing a service is using package_options to decide which things to display, but is somehow picking up existing service_options values to set initial values for those fields.
  6. It turns out: This is done by javascript if you have a min and max value. Omitting max values leaves us plain old text boxes.
  7. Okay, so, say we have virtual hosting, and because it's 1995 again, we're charging $1/month per megabyte of storage. So, a customer has a monthly service package, which includes a service addon of "storage", billed at $1/unit. So if they have 500 units of storage, they get charged $500. And for some reason, we can't actually have the service value be exact, we have to do data gathering and update things. So the invoice gets created with a placeholder service that shows quantity 1, but then someone goes, checks the space the customer's using, and edits the value on the invoice. But $1/month is too high, so people negotiate us down. So someone's getting a 50% discount on storage. So, we automatically generate a placeholder invoice, which shows them getting 1 unit of storage for $1, and then we change the usage manually to 250, which would be $250. But they get a 50% discount. So it shows them getting 1 unit of storage for $0.50, and then we change the usage manually to 250, and now it says $125. If the discount is a separate line item with a negative dollar amount, what should that dollar amount be? It should be $0.50 when storage is 1, and $125 when storage is 250. And it won't change automatically, which is annoying. Also, displaying it on the invoice is harder. But with my patch (now partially implemented, but I haven't got the UI fixed for Services yet), it's just automatic. Whatever you set the quantity to, the price is reduced by 50%. One complexity is, there's a few places which do sum(x.amount*x.qty) in SQL queries, and we can't do that. But I think that's wrong anyway, because that moves the rounding to the wrong place. Each line should be fully rounded independently. (Say you have a pro-rated invoice with two $0.25 things on it, and exactly half a term for each. Our accounting people require us to compute each line as $0.12 and total to $0.24.) So right now, the subtotal display for recurring invoices is wrong, because it's grabbing a single subtotal for the whole invoice rather than separately selecting the invoice_recur_line entries and computing their values, and I haven't figured out where to put the UI elements for editing discounts in Services, but the invoices themselves are working.
  8. As a followup: I do not at all understand the interaction between the rest of the line item computations, and the magic in core/Pricing/Presenter/Collection/CollectionItems.php and friends. They have references to "discounts" but I can't figure out what those relate to at all. They don't appear to be coupons, exactly, but I'm not sure what they are. Like, they don't appear to participate in invoice->GetSubtotal() or anything. It *looks* like the places I need to add a discount are invoice_lines, invoice_recur_lines, and service_options. With service_options controlling the creation of plain invoices from services, and invoice_recur_lines controlling the creation of plain invoices from recurring invoices. But both of those paths lead to an invoice which just has static invoice_lines. Also I can't find anything that calls invoice->makeLinesFromItems, which means I'm probably missing something.
  9. So, if I want a package option with a range from, say, 1-2048, not counting by 8s or whatever... is there any way to make this present as a text input field instead of a slider? I ask because we have some things that customers could conceivably want >32,000 of, but which they might also want exactly 1 of, which would be great package options, but so far as I can tell, exact entry would at that point require a monitor >32,000 pixels wide so the GUI element could work...
  10. I don't think it is. I can fake up the presentation however I want by overwriting the invoice template, but it seems to me that if the original line item were a package option with a number, making a separate line item for the discount means that I now need some way to track that the discount is related to the previous line item, so I know to update it if the package option gets altered. So, if someone were to edit that invoice and change the quantity of the first line to 2, the discount wouldn't necessarily track it. So I'd rather just have an actual per-line discount rate, expressed as a percentage probably.
  11. Yeah, I hear you on the Friday thing. This was a heck of a week for me, so I'm a bit fuzzy. The issue I have right now is that, without a distinct "discount" field per line item, there's nothing I can store in the existing fields that correctly indicates the state I want to indicate, which is basically "you have ten X, they're $9 each, you get a 25% discount, so that's $90-(25%) => $67.50. But we want the display to indicate the discount specifically. And we can't really achieve this with coupons. With coupons, if we make an invoice for you, and you have 10 X, and a coupon that provides a 25% discount, the discount amount is computed based on that. If we then edit the invoice to indicate that you have 12 X, the discount line item still reflects 25% of the pricing of 10 X. (This matters, in our use case, because we anticipate at least a while during which we'd be creating invoices automatically, but updating some quantities after the fact with information we haven't got properly integrated yet.) And I think that's partially just because coupons are applied at invoice generation, and then the generated invoice doesn't really have a coupon anymore, just a fixed dollar amount discount. Thinking about it, I note there's currently no model for "line items" in and of themselves. So services and invoices interact with line items, but for instance, the subtotal computation in the invoice is requesting a sum from SQL, not requesting the individual line item values and then summing them. I don't think this is enough complexity to want to make line items their own model. Anyway, I think the points that would need to be changed would be (1) line items need a discount, (2) invoice edit/view/etc need to be able to display the discount field, (3) services need to be able to record discounts on things so they can create line items with matching discounts when the services apply. And I think all of these are reasonably simple.
  12. I was looking at the event hooks, but it looks like I still can't actually do what I want with those, because the actual computation of "the cost of this line item" seems pretty baked in. And I want to be able to do things on a per-option basis. What I'm looking at specifically is: public function getSubtotal($invoice_id) { $subtotal = 0; $sub = $this->Record->select(['SUM(IFNULL(invoice_lines.amount*invoice_lines.qty,0))' => 'subtotal'], false)-> from('invoice_lines')->where('invoice_lines.invoice_id', '=', $invoice_id)->fetch(); [...] } My basic thought is to add a discount rate field to the invoice lines table, and modify this computation to use it, and then also add UI widgets to various places. But I don't think this is possible with plugins or hooks; there's no way to intercept this computation and alter it. ... Which means I'd be looking at making an actual change to core to add this feature, whereupon the question is, are you at all interested in contributed feature code? Because I'd rather not maintain a fork, but this looks like something which is almost trivial to do if it's being done in the core system, and extremely difficult to get right in a plugin. The basic goal is to just allow every line item in an invoice to have a discount rate which is computed individually-per-line-item, and can be displayed in invoices. To clarify: Part of the goal here is not just to change the values, but to have something indicating what is going on. Without a discount field, there's no easy way to know how much to change the value, and there's no way to reliably display the correct result; I could sort of fudge it by computing the expected price, comparing to the overridden price, and displaying the difference, but that'd have rounding issues, etc. So I'd rather just have the data actually model what's happening, which is something like "this customer gets 25% off on this specific package addon".
  13. Okay, so, in existing stuff that we wish to migrate to Blesta, we have line items, and every line item can have its own discount. And if the amount of a thing changes (something like storage usage or bandwidth), discounts apply to that change. In Blesta, the only discounting option I'm seeing is coupons. Coupons apply per-package, so I can't have one discount rate for one line item, and another discount rate for another. But possibly more concerningly, coupons are applied instantaneously at the time of invoice creation, and don't adjust to reflect future changes to the invoice. There's some data gathering that's gonna take time to get properly integrated/automated, meaning in some cases we'll want to edit an invoice to change the quantity of an item. But if the item's discounted, this... doesn't work. So what I'm looking for is an alternative path. I think I could make a plugin which adds a table that can record discount rates associated with services, or individual line items... But I don't see any obvious way to then override an invoice's calculations about how much it thinks is owed. I suppose I could do it the other way around, and have the plugin do the computation and set price overrides, maybe? Basically, I don't understand the architecture well enough to be sure even what I should be asking. My ideal goal would be, when creating a service subscription, to be able to enter a discount percentage for each line item separately (say, addons within a package, one customer could get 20% off package option A and 25% off option B, another could get 30% off A and 0% off B, so discounts are unique to a specific customer/option pair), and any edits to the invoice that affect quantities would still correctly reflect the discount. I'm pretty sure that the coupon system is entirely irrelevant to the intended use case here, honestly; it's at the wrong granularity and it's a one-time computation. But I don't immediately see any hooks in the plugin architecture to let me override an invoice's computation of totals.
  14. Ah-hah! Thanks. Very helpful.
  15. So, for Historical Reasons, we have a desire to generate invoices automatically from services... but not send them to customers, because there's additional business processing that has to happen first. Is this a thing that I can configure with the existing stuff, or do I need to write a plugin or something? I have not found settings for which events do or don't cause email to be sent.
×
×
  • Create New...