some plugin-developer-friendly requests

This forum is for programmers who have questions about the source code.
Post Reply
alkhaef
Posts: 105
Joined: Fri Jul 02, 2010 10:37 am
Location: Los Angeles, CA

some plugin-developer-friendly requests

Post by alkhaef » Thu Jul 15, 2010 11:44 am

Hello,

Please let me know if I'm just missing something and there's another way I should be looking at all this...

I'd like my plugins to call upon some methods in OpenDental that I can't access in some cases. One example of this I'll use is for my plugin to create treatment plans automatically based on some criteria.

I could always copy some code in the UI layer, or alternately touch the DB directly, but neither of those would be very forward compatible - when changes are made in a future version and I don't notice, my plugin will wreak havoc.

Ideally, I could get all the work done in a lower-level (e.g. OpenDentBusiness) but that has limitations as well (in some cases, some data manipulation is still being done at a higher layer in the UI handlers - Take a look at ContrTreat.OnCreate_Click).

In this particular example, either one (or both) of a couple of things would save my day:
1. A copy constructor / method for tp's -> TreatPlan's
2. PerformXXXX public methods for UI events so they can be fired from outside the class (some examples could include ContrTreat.ToolBarMain_PerformClick, FormOpenDental.ToolBarMain_PerformClick, etc)

I think having both would be very useful, although #2 could arguably encourage some bad practices.

I'd like to make sure I'm making reasonable requests going forward, so please let me know if either of these aren't.

Thanks again,
Al
Help! I've OD'ed on OD! :)

alkhaef
Posts: 105
Joined: Fri Jul 02, 2010 10:37 am
Location: Los Angeles, CA

Re: some plugin-developer-friendly requests

Post by alkhaef » Thu Jul 15, 2010 6:22 pm

Just wanted to give another example (also related to treatment plans)...

I'm trying to spit out summary information on the most recent treatment plan out to a text file. My only solution I see so far is to duplicate lots of code in ContrTreat.FillMain() (TP totals, patient portions, etc. aren't stored anywhere in the database, and are calculated on-the-fly, and there's no public way to get to them in-memory either).

Is there a better way for me to do this that I'm not seeing?

Thanks again,
Al
Help! I've OD'ed on OD! :)

User avatar
jordansparks
Site Admin
Posts: 5739
Joined: Sun Jun 17, 2007 3:59 pm
Location: Salem, Oregon
Contact:

Re: some plugin-developer-friendly requests

Post by jordansparks » Thu Jul 15, 2010 8:50 pm

I don't understand #1. #2 is fine. As for spitting out a recent TP, I think that a saved TP does far less calculation on the fly than the default TP. That's the whole point. In fact, you could probably pull a saved TP exclusively from the db if you wanted to.
Jordan Sparks, DMD
http://www.opendental.com

alkhaef
Posts: 105
Joined: Fri Jul 02, 2010 10:37 am
Location: Los Angeles, CA

Re: some plugin-developer-friendly requests

Post by alkhaef » Tue Aug 03, 2010 11:20 am

Hi Dr. Sparks,

I'm pretty sure I wasn't able to communicate my message too well, so I wanted to wait until I understood a bit more about the overall intended architecture of OpenDental before replying. It should be easier to get my question across with my laser-pointer below ;).

I'm sorry if this post is so long. I've bolded the cliffs-notes version so that you can skip to the bold stuff and refer back to the rest only if needed.

After going through the code and some threads I could find, it looks to me like for the purposes of my question, the following three distinct layers are at work:

1. UI code - code for drawing, updating, and responding to events - from homebrewed widgets (OpenDental\UI\*) to forms (OpenDental\Forms\*) to the top-level controls (OpenDental\Main Modules\*), among others...
2. "Data Interface" (OpenDentBusiness\Data Interface\*) - code for gathering and updating relevant data from the DB (e.g. basic CRUD operations), as well as business logic for manipulating and better-representing in-memory data (e.g. Procedures.GetProductionOneApt). All public. All static. Any data to be manipulated are passed as parameters. <bold guess>It appears that the goal is to have all business logic in the Data Interface as time goes on, which I think is prudent.</bold guess>
3. Data Objects (OpenDentBusiness\Table Types\*) - Closely coupled to the schema. Apparently automatically-generated to ensure consistency between program data structures and DB somehow, therefore can't be touched (e.g. helpful methods can't be added to Account.cs, but should instead be in Data Interface). All fields/methods public.

Now that semantics are out of the way, back to my two requests, each with its own example:

SITUATION 1
Data-interface solution - Based on the above, a big family of problems can be solved in a plugin by handing off most of the work to the data-interface layer. Less code in the plugin means more future-proof plugins. However, there are some cases where the business logic is sitting in the UI code, rather than in the data-interface layer. I'm guessing that cases like these only have historical, rather than technical reasons.
Example: Getting the totals of a given treatment plan - To do this, I had to copy all this code from the UI layer (specifically, the FillMain() helper function)...

Code: Select all

                ProcTP[] ProcTPList=ProcTPs.Refresh(PatCur.PatNum);
                ProcTP[] ProcTPSelectList;
                double fee;
                double priIns;
                double secIns;
                double discount;
                double pat;
                double subfee=0;
                double subpriIns=0;
                double subsecIns=0;
                double subdiscount=0;
                double subpat=0;
                double totFee=0;
                double totPriIns=0;
                double totSecIns=0;
                double totDiscount=0;
                double totPat=0;
                int j=0;
                ProcTPSelectList = ProcTPs.GetListForTP(curPtTreatPlans[j].TreatPlanNum, ProcTPList);
                for (int i = 0; i < ProcTPSelectList.Length; i++)
                {
                    subfee += ProcTPSelectList[i].FeeAmt;
                    totFee += ProcTPSelectList[i].FeeAmt;
                    subpriIns += ProcTPSelectList[i].PriInsAmt;
                    totPriIns += ProcTPSelectList[i].PriInsAmt;
                    subsecIns += ProcTPSelectList[i].SecInsAmt;
                    totSecIns += ProcTPSelectList[i].SecInsAmt;
                    subdiscount += ProcTPSelectList[i].Discount;
                    totDiscount += ProcTPSelectList[i].Discount;
                    subpat += ProcTPSelectList[i].PatAmt;
                    totPat += ProcTPSelectList[i].PatAmt;
                }
As you know, plugin developers keeping code blocks like that in their code isn't very DRY, especially given the fact that OpenDental releases major revisions so often.

So back to my question - Was my "bold guess" above correct in the sense that this (and all business-logic-type) code is intended to be in the "data interface" layer, and not the UI code? If so, that section of my plugin can collapse into just a few lines. Going forward, would it be welcome for me to identify other such sections of code that would be more in-line with the intended architecture if moved (or even patches)?

SITUATION 2
Plugin-UI interactions - Sometimes, it's the UI that the plugin intends to touch. For example, say I want my plugin to select a specific TP and pull up the "Sign TP" dialog. Right now, things like this are very difficult to pull off. The following changes would unshackle plugins and allow functionality like this example:
- All UI event handlers (OnClick, OnMouseEnter, etc) for UI classes (ODGrid, ODToolBar, ...) - made public... or public accessors added.
- Some members of UI classes made accessible (e.g. ODGrid.RowLocs, ODGrid.RowHeights, etc)
- Some members of forms/controls made accessible (e.g. ContrTreat.ProcListTP, etc)
- More controls having the Control.Name property set (e.g. FromOpenDental.Contr*, etc) so they can be searched easier

So back to my question - Is allowing control and access of the UI part of what you'd like to allow plugins to do? If I'm understanding your "#2 is fine" comment correctly, it is. If so, is the above a reasonable approach to this? And again, would it be welcome for me to identify other such candidates for plugin-accessibility?

Thanks again!
Al
Help! I've OD'ed on OD! :)

User avatar
jordansparks
Site Admin
Posts: 5739
Joined: Sun Jun 17, 2007 3:59 pm
Location: Salem, Oregon
Contact:

Re: some plugin-developer-friendly requests

Post by jordansparks » Tue Aug 03, 2010 10:24 pm

It's a big gray area between business logic and UI logic. One good way to identify business logic is if it's used more than once. Your particular code example isn't used more than once that I'm aware of and it would have been kind of a hassle to move it to the business layer with no apparent benefit. The code is so vast at this point that very little movement of code will take place. For example, we still haven't even fully implemented our CRUD automation, adding a few more tables with each version. So I would say to just adapt to the code as it is currently written unless you find something awful.

public members for:
UI event handlers: no problem. It's going to feel a little weird, but it shouldn't be confusing to anyone. "All" is vague. We do have limited resources, so specific requests are best.
Members of UI classes: This is going to make an elegant control look sloppy and confusing. Maybe if we stick with Get... and use a comment to clarify why it's public, then that would be ok.
Members of forms/controls: no problem.
Control.Name. Really? We missed this? The names are terrible, but I guess we'll stick with them out of expediency.

Yes, definitely.
Jordan Sparks, DMD
http://www.opendental.com

alkhaef
Posts: 105
Joined: Fri Jul 02, 2010 10:37 am
Location: Los Angeles, CA

Re: some plugin-developer-friendly requests

Post by alkhaef » Wed Aug 04, 2010 10:07 am

Dr. Sparks,

Thanks for the clarifications. I'll make some specific requests within the boundaries you've laid out.

Best,
Al
Al
Help! I've OD'ed on OD! :)

kdna
Posts: 15
Joined: Wed Feb 22, 2012 12:59 am

Re: some plugin-developer-friendly requests

Post by kdna » Mon Aug 27, 2012 2:47 pm

I am having issues getting the Example Plugin working. If you have something working, I would love to see the code. The docs are lacking.

Thanks.

User avatar
jordansparks
Site Admin
Posts: 5739
Joined: Sun Jun 17, 2007 3:59 pm
Location: Salem, Oregon
Contact:

Re: some plugin-developer-friendly requests

Post by jordansparks » Wed Aug 29, 2012 12:07 pm

The docs kind of assume that you're a programmer who is going to take the time to look at the code and figure it all out anyway. If you're not going to dig that deep, then any plugin you write would be flawed and buggy anyway, right?
Jordan Sparks, DMD
http://www.opendental.com

Post Reply