In the last episode, we set up the chart of calculations that we called WorkTypes and saw how different work types displace each other. We also learned how to read the displacement-adjusted data and how to calculate the weekly earnings.
My next challenge is to sum up the monthly earnings and calculate a bonus as a percentage of this sum.
So, in this case we use a result of one calculation to calculate another type of earning. In 1C:Enterprise we say that the Total calculation is a baseline (or simply the base) for the bonus calculation.
This is what we are here to discuss today.
To adjust its records according to the displacement settings the calculation register needs to know the only thing - what displaces what. To calculate the bonus as a percentage of the monthly earnings the register needs to know the result of this baseline calculation.
The only place we store this result so far is this tabular section attribute of the Payroll document down here. For the register to be able to sum up the baseline earnings we need to store them directly to the register first. This is what we use calculation register resources for.
So, I’m adding a new resource called Wage right here. To write any record to the register I have to give it a reference to this chart of calculations. This new calculation type will be used in the source code, so it needs to be predefined. So, I‘m going here and adding a new predefined calculation like this. With this new record in the chart, its name doesn’t sound right anymore, so I’m renaming it to EarningTypes like this.
Now. This is the document that should post its records to the calculation register. So, I’m going in, turning on the posting, selecting the register I want to post to and running the wizard. This is the document’s tabular section. Mapping its attributes to the register. And this is where I should put the reference to my predefined hourly wages calculation type. So, here it goes. I also need to fix this end of period mapping, like this. And this is my posting event handler procedure.
OK. Let’s see how it works. This is our Payroll register with all the data about time worked by Agnes and Dany. Now I’m going to last week’s Payroll document which now has the Post button. So, I’m clicking it and here are my cashiers’ weekly earnings in the register. Great.
Now I can register all the time worked over the last four weeks and post Payroll documents for every week. Except when I try to post this document for the last week, this happens. So, the record is invalid and it has something to do with the period of time this earning is registered for.
Let me explain this. The calculation register has this setting called periodicity that is set to Month by default. This setting tells the register to always keep each earning inside a single period of this length and never let it sit between two chairs. There are these four options available and the selected one prevents any register record from crossing month boundaries.
But what is so special about this boundary? Why do we have to respect it so much? Because this is all about your tax obligations, which are always periodical. If you work for a company that pays you salary, the company also has to pay so-called remittance to the tax agency. The frequency of remittance payment is set by the tax authority, and in the most common case it’s once a month. Self-employed pay themselves, so the taxes are their personal responsibility. In most tax jurisdictions the tax return is due once a year. So, the register periodicity in this case should be set to yearly.
Your remittance for a period is calculated as a percent of all earnings during this exact period. If any earning sits between two periods, you cannot tell how much exactly was earned in any of these periods, so the remittances become impossible to calculate. This is why you just have to assign each earning to one specific period of time according to the register’s periodicity settings.
My payroll remittance is due once a month so the register’s periodicity is Monthly, and to get rid of this error message, I need to break this single document into two separate ones: one for December and another one for January. And these are my hourly wages in the calculation register.
To add a Bonus earning and make it dependant on the Hourly Wages we need to go to the chart of calculations, and turn this Depends on base flag on. This checkbox over here tells that this base-dependency exists between different records of the same chart, so I’m turning it on too. And as soon as I do, this standard tabular section gets enabled.
So, I added this table to the chart’s form over here, and now I can add the Bonus earning and tell it that it should be based on the hourly wages. I also need some place to store the bonus percentage itself, and this Rate attribute looks good enough for the task, except for some minor appearance changes. Which I already did behind the scenes, so here it goes.
First, I added a new enumeration called RateTypes to tell the earnings rated in dollars per hour from the percentage-based earning like bonuses and such. Then I went to the Chart and added this RateType attribute having this enumeration reference type and renamed the HourlyRate attribute to Rate. Then I retrofit the Chart form By adding this RateGroup that combines both RateType and Rate attributes as well as this label field to hint a user what units this Rate value is measured in.
Then I added a few event handlers to the form’s module. One of them is triggered whenever the RateType value is changed. The handler calls this server procedure to set the label to dollars per hour or percent depending on the RateType value. The second handler is triggered when the form gets created and does exactly the same - updates the label text.
So now, I can open the Bonus earning set its type to Percent and set its Rate to ten percent. Great.
We already have our hourly earnings ready to be fed to the bonus calculation, so, we can ask the register to sum up Agnes’s and Daniel’s earnings over the month. And the form this question should be asked in is adding two new records to the same register: one for Agnes, and one for Danny.
We should specify the BONUS earning type for both records and we also need to tell the register which time interval it should use to sum up the baseline earnings. We call this interval a base period, and for the December bonus it should be set from December 1 to December 31. As soon as it’s done, the register will grow itself a virtual field called BaseEarning and sum up all of December’s hourly wages for Agnes and Danny.
And this is how I implemented this piece of functionality. First of all I switched on this flag that tells the register to enable these Base Period standard attributes over here. I also renamed the register’s resource from Wage to Earning so the name better fit our Bonuses. Then, I retrofit the register form by adding this new tab over here and dropping this new dynamic list to it.
The list executes this query that grabs the data from this virtual table over here, whose only mission is to give us this BaseEarning summed up and ready to go to our bonus calculation. Basically, this virtual table performs this kind of subquery for us.
Usually, virtual tables like this one group the aggregates by all the dimensions, but the calculation register is more flexible and gives us this parameter, so we could choose some of the dimensions ourselves. And this is where I set the parameter value by creating an array with string “Cahier” in it and passing it to the dynamic list like this.
One more thing I did is create this Bonuses document, whose purpose is to write its tabular section to the calculation register and set the base period for them.
And this is how it all works. These are my Bonuses documents. I’m creating a new one. Setting up the base period. Adding bonuses for Agnes and Danny. Posting these records to the register. And these are the base earnings the register calculated for us.
So, the only thing left for us to do is to read these records back from the register and calculate the Bonuses.
And this is how I did it. First of all, I added this Calculate button to the Bonuses document form. The button click triggers this Calculate command, which in its turn runs this server-side procedure, and this is what’s going on down here.
First, I need to write the bonus records to the register, which is the definition of the document’s posting, right? So this is exactly what I do here: I call the document’s Posting method. And to be able to do this, I’m taking this Object form attribute and converting it to document object. I also had to make some changes in the Posting method itself. Namely, I made it accessible from the outside and added this explicit Write call in the end. This is how I get bonus records written to the register.
Next, I read from the database the tabular section records belonging to the document we’re currently working with. Not that I need it myself, because the entire document already sits in the memory. But I do it anyway, so I could join this register’s virtual table and grab these baseline earnings it calculated for me on the fly. Then I just multiply the base by the rate taken from the chart of calculations and divide the result by one hundred because the rate is in percent.
And these are my cashier bonuses calculated in one shot.
This piece of code here is just same old parameter setting. Executing the query. And then I just cycle through the query results and write the bonus directly to the document object opened in the form. And, yes. I added this Bonus attribute right here to the tabular section as well as here - to the Posting event handler, so the bonuses go to register, and you can build other calculations on their basis if need be.
OK, running the app. This is my Bonuses document that now has this new attribute in the tabular section. I click Calculate. And these are this month bonuses for Agnes and Danny. Awesome.