Today, we will have a look a the taxes and cards with tax refund.
Taxes are quite high at the moment. They even go higher than 100%. Fortunately for us, they are capped at 100%! Today taxes are at 108.343%, but I only pay 97.5% as I do own a Law Firm.
Some cards give a "tax refund" : for each card you own, you get 1 SIM refund on your taxes. Let's put it another way : some cards have a 1 SIM income, not subject to taxes. The refund is limited to the amount of taxes you are paying. As I pay 3900 SIM in taxes and only 25 SIM in refund, I guess I should now worry about being limited anyway :D.
The goal of this post is two sided :
- First I'll compute my actual taxes
- Then, I'll add the tax refund in the calculations
The highest APR card with taxes, as of today, for the lazy readers !
For those who don't want to read all the technical details, when you take the taxes and tax refund into account, the highest achieavable APR is 66% and is a Citizen. Welcome to the podium, Student !
The first building is the Forest (not really a "building" 😅), with an APR of 16%.
Interestingly, even with 98% taxes, the best building with a tax refund is the Church, with only 14% APR, and that's with 8 Advanced Prayer tech cards ! That's because it's sooooo expensive : 2755 SIM at flow run time.
Current Taxes
You should have read my previous post to understand what's next !
@cocaaladioxine/dcity-card-with-the-highest-roiapr-part-2-technology-cards
The best way do add a subjob is to deactivate the previous development, and develop and create your new subjob before joining the data. To deactivate a subjob, right click on a starting component (green background) and "deactivate whole subjob".
tRestClient: Call dCity API stats for taxes
You saw this component already. Nothing changes, we gets the global stats:
tExtractJsonFields : Extract Taxes & lobby
Taxes values are here :
Lobby also influence taxes as you can see in the first screenshot, so we need the lobby value.
All those data are mapped by their JSON path :
tMap - compute taxes :
The income tax reduction is capped at 20%, and the war tax increase capped at 10%. So we'll multiply them by 0.2 and 0.1.
The global tax computation is :
Java
taxes_and_lobby.tax_int - Var.income_tax_reduction + taxes_and_lobby.tax_pot + taxes_and_lobby.tax_edt + taxes_and_lobby.tax_art + taxes_and_lobby.tax_war + Var.war_tax_increase + taxes_and_lobby.tax_ect + taxes_and_lobby.tax_jot + taxes_and_lobby.tax_bat
tLogRow :
This is a simple terminal logging component : it prints the rows to the standard output, which is located in the bottom part of the screen.
We can see here that I computed a 108.343 tax, which is exactly what we expected (see first screenshot)
And the Law Firm ??? And the tax capping at 100% ??
Yup, we should take this into account.
Now that I know that my calculation are good, let's make some changes. We need to know if we have a Law Firm. And we already get this data in the first part of the job.
As it's usually the case with Talend, there are multiple solutions here. I will use variables to transfer the data to the tax part of the job.
tSetEnv : Set Var for Law Firm
This will instantiate a global variable "law_firm" with a default value of 0.
tReplicate : copy flow
This component copy the incoming flow as many time as you need.
The processing inside a subjob is sequential (altough you can parallelize multiple subjobs).
Thus, there is a processing order on the output flows. Let's set "active_cards_for_law_firm" as the first one.
tFilterRow : get the law firm
That's a basic configuration : just keep the law firm if there's more than 0.
tSetEnv : Set Var for Law Firm
I kept the same name as the first one as it does exactly the same. Note on the previous screenshot that there is a "if" on the link between "Get the law firm" and the tSetEnv. The idea is that I want to trigger the second tSetEnv, only if there is at least one card named "2_lawf". There will be only one line in the tFilterOutput if we got a Law Firm, zero if we don't.
The condition is thus :
Java
((Integer)globalMap.get("tFilterRow_3_NB_LINE_OK")) >= 1
Each Talend component "emits" variables. They are listed in the outline :
You just need to drag drop them to get the syntax !
tFilterRow_3_NB_LINE_OK is the number of line matching my filter condition.
The final tSetEnv value must now be set to 1.
tMap : compute taxes
Back to compute tax tMap: create a new Variable named law_firm_correction.
Java
((String)System.getProperty("law_firm")) == "1" ? 0.9F : 1F
90% taxes if there's a law firm, 100% if not.
Then update the full_taxes value :
Java
(taxes_and_lobby.tax_int - Var.income_tax_reduction + taxes_and_lobby.tax_pot + taxes_and_lobby.tax_edt + taxes_and_lobby.tax_art + taxes_and_lobby.tax_war + Var.war_tax_increase + taxes_and_lobby.tax_ect + taxes_and_lobby.tax_jot + taxes_and_lobby.tax_bat ) * Var.law_firm_correction
Seems perfect to me !
Now just clean up the tMap as we only need the full taxes !
The 100% tax capping will be handled later.
Tax Refund
My data source did not mention the tax refund. Once again, there is only 5 cards, so the data source will be updated manually.
Took me less than a minute !
Metadata : dcity_cards_definitions
Now it's time for a little Talend magic !
When I added the tax_refund entry, I changed the schema. So, I'll update it :
That's it! When clicking "Finish", Talend will update the jobs and my tFileInputJson now shows the tax_refund mapping.
Putting all together
We now feed the taxes to the "Map Ask to card definition" tMap.
As we want to have the tax value everywhere, we won't even need to define a joining key.
It's time to take the tax capping into account, with a Variable, named *capped_tax *:
Java
taxes.full_taxes > 100F ? 0F : 1 - (taxes.full_taxes / 100)
We should also put a failsafe on the tax_refund field, to prevent Null values :
Java
cards_definitions.tax_refund == null ? 0 : cards_definitions.tax_refund
Now add a taxed_apr field in the output row, and add the tax_refund and capped_tax:
Java
Math.round(Var.price != 0 ?
(
(
(
( (Var.income + Var.income_boost) * Var.capped_tax )
+ Var.tax_refund
)
* 365 / Var.price
) * 100
) : 0
)
The final job with the stats :
It's still less than 3 seconds overall, with the main waiting time coming from the API calls.
Conclusions
I have to admit that I expected more from the tax_refund and the church especially.
It's still very intersting on the Student card, with a sweet APR of 66%. The advantage being that this revenu will remain the same, unless taxes go to 0, or you have thousands of students. Fortunately, my actual audience is quite small, so I hope the Student price won't skyrocket! As it also bring 1 population and 1 popularity, the Student is a really nice card to hold !
In the next episode
I'll probably do some purely technical improvements. I'd like to store the data in a Google sheet, and have a little Datastudio connected to it. I'll continue to post the highest APR card at the beginning of my post, but the calculation won't change.
Feedback
Don't hesitate to give me feedback ! I want to improve my presentation, teaching and English skills !