Compare commits

..

370 Commits

Author SHA1 Message Date
54921f0e85 If price (=key) is not found, compute the next smaller valid price (=key)
and use this as maxPrice.
Usage: (Innichen (508) with) direct coin input.
2025-04-17 13:33:22 +02:00
077c2334ca Restore pop_max_price in case it has been changed (for certain settings). 2025-04-17 13:09:53 +02:00
d605af5c5a Check prepaidIf and carryOverIf for null and emptyness. 2025-04-16 11:32:20 +02:00
c5900f9f2b Minor: extend debug output 2025-04-16 11:31:05 +02:00
9b137c2873 Fix in Calculator::GetPriceForTimeStep():
Allow some tolerance (of 3 minutes) when looking up the
	current time-step value in the duration-array.
	Otherwise, when corossing a minute-boundary, it can happen to
	not find the match and returning a price of 0 (which is almost
	always wrong).
2025-04-03 11:53:47 +02:00
dd249a87d5 Set cnt-limit to 20. This allows a bigger time-range for tariff, which
have in principle no time-limit.
2025-04-02 15:28:46 +02:00
575885c19e Merge branch 'master' into kleipeda-experimental 2025-04-02 09:44:20 +02:00
d82a732a8d if end of parking time equals carry-over-end, then, if configured, go back to carry-over-start. 2025-04-01 14:26:21 +02:00
99dbd7c194 Minor: debug output. 2025-04-01 14:24:42 +02:00
ae985d25ce
Merge branch 'kleipeda-experimental' 2025-02-04 14:58:58 +01:00
6a215d4cf9
Allow zone_nr > 999 2025-02-04 14:47:07 +01:00
a3f4a742ce
Read zone_nr from system_data 2025-02-04 14:44:28 +01:00
e6d8c04076 Fix: for time change summer -> winter term. Compute minutes until midnight manually. 2024-10-30 15:56:58 +01:00
1f6606f382 Add some tests for Forchach (749) 2024-10-10 11:40:29 +02:00
4b9a4319b3 ComputeDurationFromCost():
Fix: take into account that there may be more than just two
	carry-over-ranges. For instance, in Korneuburg (714), there are three
	as they have a break from 12:00-14:00.
2024-10-10 11:38:14 +02:00
5e673788b4 ComputeDurationFromCost():
Use helper function computeMinutesUntilCarryOverEnd() to compute
	the offset until the end of the carry-over-range.
2024-10-10 11:36:14 +02:00
7e2f40a7b5 Add assigment-operator (otherwise compilation error). 2024-10-10 11:33:33 +02:00
44e2ce24a3 Add helper computeMinutesUntilCarryOverEnd().
Used in new tariff-calculator. Replace of previous wrong approach of
        using m_range.duration.
2024-10-10 11:30:53 +02:00
5a55ad6ef0 ComputeDurationFromCost():
brutto-time must be updated in case of an carry-over-section.
2024-10-02 15:21:21 +02:00
5a77958e8d getOutOfService():
Check for special days (holidays) with out-of-service-time-ranges.
	Holidays have higher priority than usual days ("default").
2024-10-02 15:19:32 +02:00
a1e7f4629a getService():
Check for special days (holidays) with service-time-ranges.
	Holidays have higher priority than usual days ("default").
2024-10-02 15:18:16 +02:00
efc2582c36 getCarryOver():
Check for special days (holidays) with carry-over-sections.
	Holidays have higher priority than usual days.
2024-10-02 15:17:00 +02:00
a72f5a5019 getPrepaid():
Check for special days (holidays) with prepaid sections.
	Holidays have higher priority than usual days.
2024-10-02 15:15:19 +02:00
28f0ea9fce Merge from kleipeda-experimental-snapshot-2024-09-27:
started new implementation of tariff-calculator.
2024-10-01 09:25:53 +02:00
3109e82ef8 If out-of-service, use start of out-of-service action as output-date. 2024-10-01 09:23:15 +02:00
03dd6c44da Always reset pop_max_price to configured value. 2024-09-30 16:58:23 +02:00
212c792b77 compute_price_for_parking_ticket():
Include opverpaid option in price-computation.
2024-09-30 16:57:18 +02:00
ab3cdb32ae compute_next_timestep():
Restrict time-step-list when time-limit has been reached: +/-_button
	does not move upward anymore.
2024-09-30 16:55:25 +02:00
4f23ab3d68 ComputeCostFromDuration():
Add price when overpaid occurred.
2024-09-30 16:53:25 +02:00
acbc27cfb2 ComputeDurationFromCost():
If overapid or trunctae has been set, then truncated max. parking time
	to time-limit configured in tariff-file.
2024-09-30 16:51:51 +02:00
bcbe95d483 Add hard-coded trauncate flag. 2024-09-30 16:51:02 +02:00
e3bbca86d5 Minor: changed parameter type to non-const. 2024-09-30 16:50:21 +02:00
5868d3b510 Introduce computational state 2024-09-30 16:46:36 +02:00
d4363e71cd Keep bacjward compatibility before using payment-method Unified. 2024-09-27 14:24:10 +02:00
fd99c20bd9 Take into account new payment method 'Unified' to call new tariff-calculator. 2024-09-27 14:20:20 +02:00
dbccdba9fe isParkingAllowedForWeekDay():
Minor: adapt function call to changes parameter arity.
2024-09-27 14:18:31 +02:00
b035f4f887 Calculator::GetDurationFromCost():
Minor: move scope of some variables upward.
2024-09-27 14:17:35 +02:00
18f09fccb9 GetDurationFromCost():
Call ComputeDurationFromCost() of new tariff calculator for payment-method Unified.
2024-09-27 14:10:02 +02:00
1086e360e5 Start of implementing new tariff calculator:
Added serveral helper function for parsing tariff file:
	  * getPrepaid()
	  * getCarryOver()
          * getService()
          * getOutOfService()

	Added main functions of tariff calculator:

	  * ComputeDurationFromCost()
	  * ComputeCostFromDuration()
2024-09-27 14:04:39 +02:00
ada7bebd90 Minor: Add headers. 2024-09-27 13:57:30 +02:00
2b9ea67ef5 Added function to implement new tariff-calculator:
std::pair<CalcState, QDateTime> ComputeDurationFromCost(Configuration const* cfg, QDateTime const &startDatetimePassed,  int cost);
std::pair<CalcState, std::optional<int>> ComputeCostFromDuration(Configuration const* cfg, QDateTime const &startDatetime, QDateTime &endDatetime, int nettoParkingTime);
2024-09-27 13:48:30 +02:00
d117328bed Minor: removed default parameter in constructor 2024-09-27 13:47:26 +02:00
fd04531474 Added payment <unified> payment-methode 2024-09-27 13:45:45 +02:00
5749fa422e Added structures for parsing of tariff05 in bad neuenahr 2024-09-27 13:45:04 +02:00
1347f1f208 Added parsing for tariff05.json (bad neuenarh (249)) 2024-09-27 13:44:01 +02:00
576c3fefdd Added PaymentMethod::Unified 2024-09-27 13:42:44 +02:00
9ca7018fc1 tests for bad neuenahr 2024-09-27 13:42:04 +02:00
515dfaf35c reprogrammed to use ATBTime class 2024-09-27 13:41:30 +02:00
0ab833709c Added struct ATBTariffCarryOver 2024-09-27 13:40:18 +02:00
8e4f47c7b6 Added struct ATBTariffPrepaid 2024-09-27 13:39:35 +02:00
bc9645f1fa Minor: removed "pragma once" compiler flag 2024-09-27 13:38:39 +02:00
713b483918 Added/fixed several functions. final testing needed. 2024-09-27 13:37:54 +02:00
3c7af1cb32 Minor: Added tariff_service and tariff_out_of_service 2024-09-27 13:35:54 +02:00
356e451839 Add structures to encode service and out-of-service times 2024-09-27 13:35:03 +02:00
c4e1d412a5 Add some assinment operators to support assignment of tariff-time-ranges. 2024-09-27 13:31:01 +02:00
1b716c48d2
Fix: copy header files 2024-09-19 14:10:05 +02:00
77e1414c13 compute_duration_for_parking_ticket():
Recompute pop_max_price using netto-parking-time.
	Search Duration for the time-step with time-step == netto-parking-time,
	then search for the corresponding price in PaymentRate.
	The result is the new pop_max_price.
2024-09-17 17:05:23 +02:00
d95275a72d Compute real netto_parking_time.
This time will be used to find the real time-step, and from here the actual price to pay.
2024-09-17 17:04:27 +02:00
577a17dc6a Set seconds of serveral date-times to 0.
Compute netto_parking_time (which includes carry-over duration).
2024-09-17 17:03:29 +02:00
d8d32820a3 compute_price_for_parking_ticket():
Reset pop_max_price to original value using pop_max_price_saved.
2024-09-17 17:01:32 +02:00
2ce0aeef1d Minor: include atb_time.h 2024-09-17 16:59:07 +02:00
0cba85eafb Set pop_max_price_saved 2024-09-17 16:58:20 +02:00
4030a4b165 Add pop_max_price_save in case pop_max_price has to be re-computed dynamically, so it can be reset 2024-09-17 16:57:34 +02:00
8c7afdfcb1 Add additional constructor. 2024-09-17 16:53:45 +02:00
932d4e8cb9 check it ticket-end-time hits carry-over-start. if configured, move to end of carry-over. 2024-09-16 16:56:48 +02:00
38abc65425 compute_price_for_parking_ticket():
Check if minutesUntilCarryOver is positive (usually must be).
2024-09-16 16:54:25 +02:00
205896903b Handle SUCCESS_MAXPRICE (calc-state). 2024-09-16 16:53:44 +02:00
dbedfd094f Add some OTHER files 2024-09-16 16:52:00 +02:00
57b9d16abc GetDurationFromCost():
Handle carry-over for direct coin insertion.
	Carefully check if this might be a problem for other projects.
2024-09-16 16:50:16 +02:00
48afbc071c Added new calc-state: SUCCESS_MAXPRICE.
Return whenever cost (=price) equals max-price.
2024-09-16 16:49:00 +02:00
7a7b10260a Add untracked(!) files 2024-09-16 16:47:01 +02:00
1874b08210 Merge branch 'kleipeda-experimental-snapshot-2024-09-12' into kleipeda-experimental 2024-09-16 10:49:23 +02:00
88a0ebb688 Add atb-time. 2024-09-16 10:42:56 +02:00
a8ae9fc602 Add own Time class (similar QTime) 2024-09-16 10:42:08 +02:00
7c0514e241 save current state 2024-09-13 10:42:45 +02:00
f53e9ceaae Some testing added 2024-09-11 12:11:49 +02:00
dffc6e2a03 Minor: removed some debug output. 2024-09-11 11:56:06 +02:00
f9cc3af473 ParseJson():
Add parsing of "pop_apply_carry_over_to_ticket_endtime".
2024-09-11 11:55:03 +02:00
9dd0108731 ParseJson():
Add parsing for prepaid-options.
2024-09-11 11:54:16 +02:00
fa10ea4b89 compute_price_for_parking_ticket():
In case parking-time-limit is violated, return with an error.

	Commented out: use another possiblity: cut max-parking-time
	so that parking-time-limit is not violated.
2024-09-11 11:49:31 +02:00
05f03a623b compute_price_for_parking_ticket():
If after crossing a carry-over-time range (taking several days)
	check if we have to carry over again on the target day.
2024-09-11 11:47:50 +02:00
03e9076962 compute_price_for_parking_ticket():
Minor: add some debug output.
2024-09-11 11:46:36 +02:00
5dbd3645c6 compute_price_for_parking_ticket():
Fetch prepaid-option-id (possibly recalculating it depending
	on year-period), and fetch associated prepaid-options.
2024-09-11 11:44:09 +02:00
d21f69cb9b get_maximal_parkingprice():
Fetch maxPrice directly instead of using utility function.
2024-09-11 11:42:15 +02:00
e38a1bfe12 Add default constructor, update debug output. 2024-09-11 11:40:19 +02:00
f38a8d528c Minor: add getters for parking-time-limit. 2024-09-11 11:39:16 +02:00
08a593eb12 Add 'pop_apply_carry_over_to_ticket_endtime':
If ticket-end-time exactly hits the start of a carry-over-time-range,
	the move to the end of the carry-over-time-range, even if this
	were not strictly necessary.
2024-09-11 11:36:57 +02:00
f322d30e36 Add default constructor, fix debug output. 2024-09-11 11:35:17 +02:00
7a53a68850 getPaymentOptionIndex(): add start-time parameter 2024-09-06 12:05:41 +02:00
275c3ec869 compute_price_for_parking_ticket():
Pass start-date-time to parking-time-checker.
2024-09-03 11:19:23 +02:00
6d2bde1fe9 getPaymentOptionIndex():
Fix: make sure only one payment option can be chosen.
2024-09-03 11:17:31 +02:00
f02521d3c2 parseWeekDay():
for the park-time-limit checking take into account that the
 	start-date-time and end-date-time are on different days.
2024-09-03 11:15:08 +02:00
75f1c1bb76 Checking parking-time-limit:
provide start-date-time as well, because the limit counts only
	from one day to following day (e.g. Sunday to Monday or from
	holiday to next day).
2024-09-03 11:10:24 +02:00
f47695de8b Add pop_plus_steps_saved 2024-09-02 17:16:47 +02:00
cce3db301b Minor: comment out some code to prevent compiler warnings (about some unused
variables).
2024-09-02 17:15:33 +02:00
5cab0de9fb Use free function getPaymentOptionIndex() to compute index of valid
payment-option-section in tariff-file based on configured businessHours.
2024-09-02 17:14:20 +02:00
f92906f680 Minor: debug output. 2024-09-02 17:13:11 +02:00
8cdeef26fc Check if computed ticket-end-time violates a carry-over-limit defined in
tariff-file.
2024-09-02 17:11:48 +02:00
52ebbf7bc9 Use free function getPaymentOptionIndex() in serveral places to compute valid
index of a payment-option-section within tariff file. If this is not possible,
then try the already available functionality.
2024-09-02 17:09:26 +02:00
349e9d8b06 Add free functions isHoliday() to check if the current day is a holiday
and previousDayHoliday() to check if previous day (relative to endtime) is a
holiday.
2024-09-02 17:05:32 +02:00
68a1c24861 Add free function getPaymentOptionIndex():
Compute payment option index base on current start-date-time and
	businesshour-setiing in tariff-file.
	Returns -1 to indicate error.
2024-09-02 17:03:37 +02:00
c946c106d1 Configuration::ParseJson():
Save the pop_plus_steps setting: sometimes it is necessary to adapt the
	pop_plus_steps-variable in order to hit a time-limit-boundary exactly.
	Otherwise the next computed time-step might overshoot the time-limit,
	and when moving backwards (via Minus-Button) there is a better
	resolution: going backwards, the user could hit the exact time-limit,
	which he could not when going up.
2024-09-02 16:58:34 +02:00
f24f1fe646 Configuration::ParseJson():
Call parseWeekDay() to reading the week-day-settings.
2024-09-02 16:57:11 +02:00
c6b8a37263 ParseJson():
Minor: some reformatting of source code.
2024-09-02 16:55:48 +02:00
58d8f16681 ParseWeekDay():
Parsing "Monday" - "Sunday" section i a tariff-file.

	Each day has a memebr named "week_day_default".

	It contains the valid default tariff settings for a usual day (i.e. no
	holiday etc.)
	It also contains the carry-over-settings for the usual day.

	In case there is some holiday on this day (for instance on "Monday"),
	the the date of the holiday replaces the name "week_day_default".
	Otherwise the structure is the same as for a usual day.
2024-09-02 16:49:21 +02:00
431664d8b9 IdentifyJsonMember():
Add "Monday" - "Sunday" as level-1 sections in a tariff-file.
2024-09-02 16:47:46 +02:00
53cf9a7341 Add description for tariff-settings.w 2024-09-02 16:46:00 +02:00
3a18ee2d7c Add description for carry-over-settings 2024-09-02 16:45:35 +02:00
929a8a4a27 Reuse of "class ATBWeekDays":
Description of a weekday: Mon-Sun. For holidays contains a type-flag
	to indicate such a day.

	Each weekday has some tariff-settings and some carry-over-settings.
2024-09-02 16:41:26 +02:00
2b9657787d add tests for bad-neuenahr 2024-09-02 16:40:38 +02:00
eca285cc25 remove obsolete print-function 2024-09-02 16:40:07 +02:00
bda8914f1a Add free functions:
previousDayHoliday():
	Check if previous day was a holiday. Check is done relative to
	computed endtime.

isHoliday():
	Check if startDateTime is on a holiday.

getPaymentOptionIndex():
	Compute the index of the payment-options-section inside a tariff-file.
	This is done as workaround (and backward compatibility).

parseWeekDay():
	Parse new structure of tariff-file.
2024-09-02 16:35:25 +02:00
a3983ed427 check for time-step-config == STATIC 2024-08-21 17:46:35 +02:00
f8805e9e78 compute_duration_for_parking_ticket():
Fix: handle carry-over for coin-insertion.
2024-08-21 15:40:55 +02:00
7a6360f392 compute_duration_for_parking_ticket():
Fix: handle prepaid-setting for coin-insertion.
2024-08-21 15:39:44 +02:00
08a249f393 return OVERPAID in case overpay is not allowed 2024-08-21 15:39:05 +02:00
7c173ae292 parse for pop_allow_overpay 2024-08-21 15:38:06 +02:00
80637260f3 Utilities::IsYearPeriodActive():
Fix: take into account if start-date <= end-date or not.
	     Otherwise check is wrong, and no valid year period is returned.
2024-08-21 15:35:03 +02:00
9b524d63e5 Add 'pop_allow_overpay' setting: set vai tariff-file if operpay is allowed. 2024-08-21 15:33:02 +02:00
25b3143d88
Merge branch 'kleipeda-experimental' of /home/siegert/atbfs01entwicklung/Elektronik/PTU/git_bare_repos/libmobilisis-calc into kleipeda-experimental 2024-08-02 14:37:42 +02:00
0856f10ca9 GetDurationFromCost():
Fix computation of end-time when pop_accumulate_durations is set
	in tariff-file.
2024-08-02 14:34:44 +02:00
88c703ecc2
Merge branch 'kleipeda-experimental' of /home/siegert/atbfs01entwicklung/Elektronik/PTU/git_bare_repos/libmobilisis-calc into kleipeda-experimental 2024-08-02 13:21:54 +02:00
465b2274a1 compute_duration_for_parking_ticket():
Adapt end-time in case it is midnight: 00:00 -> 23:59
2024-08-02 13:15:11 +02:00
f946cd13e4
Merge branch 'kleipeda-experimental' of /home/siegert/atbfs01entwicklung/Elektronik/PTU/git_bare_repos/libmobilisis-calc into kleipeda-experimental 2024-08-02 11:55:12 +02:00
8d1cbe7337
Merge branch 'kleipeda-experimental' of /home/siegert/atbfs01entwicklung/Elektronik/PTU/git_bare_repos/libmobilisis-calc into kleipeda-experimental 2024-08-02 11:29:10 +02:00
62c52fd580 test case for fuchs, fane alm. 2024-08-02 11:13:50 +02:00
1023f6ede1 GetPriceForTimeStep():
Use "pop_accumulate_durations" setting to sum up the durations.
	Otherwise time-step will not be found in time-step-list.
2024-08-02 11:12:07 +02:00
36b3e85d1b GetCostFromDuration():
recompute timestep list to make sure that time step is found in it.
2024-08-02 11:11:20 +02:00
b394ed46cc In case end-parking-time ends with 00:00, set it to 23:59. 2024-08-02 11:09:20 +02:00
3dda2d8355 Check if prepaid-option is set. 2024-08-02 11:08:52 +02:00
1152c3824e Minor: add some debug output. 2024-08-02 11:08:32 +02:00
4271c0fb31 Fixed compute_next_timestep() for degressive tariff:
compute_next_timestep() was actually never called for such a tariff.
2024-08-02 10:50:25 +02:00
24d9d4a0ff test case for kleipeda and fuchs 2024-08-01 16:46:09 +02:00
4bce854d77 GetDurationFromCost():
Set durationInSecs in case 'pop_accumulate_prices' is not configured
        in tariff file.
2024-08-01 16:44:06 +02:00
138221759b GetDurationFromCost():
Minor: removed some debug ouput
2024-08-01 16:43:19 +02:00
9cb7d4aea6 compute_price_for_parking_ticket():
Added handling for prepaid and carry-over.
2024-08-01 16:04:57 +02:00
cde490bab2 compute_next_time_step():
Added handling with pop_plus_steps/pop_minus_steps:
	'+' usually takes more than one time step.
        '-' is usually 1.

	Changed behaviour when current time is not found in the list of time steps:
	Search for the entry with the smallest distance to 'current time'.
	If the distance is smaller than 3 minutes, then use 'current time' as new
 	entry in the list of time steps.
2024-08-01 16:00:10 +02:00
f0677374ec Parsing of pop_plus_steps/pop_minus_steps 2024-08-01 15:46:49 +02:00
89b05ffadc Added GetYearPeriodActive() to get active year period. 2024-08-01 15:45:50 +02:00
260973cd09 Added pop_plus_steps/pop_minus_steps to control step sizes 2024-08-01 15:44:06 +02:00
3a98a14eb0
Merge branch 'kleipeda-experimental' of /home/siegert/atbfs01entwicklung/Elektronik/PTU/git_bare_repos/libmobilisis-calc into kleipeda-experimental 2024-07-31 10:50:03 +02:00
7bf7108668 GetDurationFromCost():
Check if computed duration is below minimal parking time.
2024-07-31 10:26:47 +02:00
e5629ba4fd GetDurationFromCost():
Check if given price is below minimal parking price.
2024-07-31 10:25:03 +02:00
0d0d34cb87
Merge branch 'kleipeda-experimental' of /home/siegert/atbfs01entwicklung/Elektronik/PTU/git_bare_repos/libmobilisis-calc into kleipeda-experimental 2024-07-31 08:06:45 +02:00
e4cb992aae GetTimeSteps() for payment-method degressive. introduced for Valser Alm (location: Fane). 2024-07-30 15:39:55 +02:00
cdeb625a15 Minor: Revode debug output. 2024-07-30 15:39:35 +02:00
589d89b73a Calculator::GetDurationFromCost():
Compute duration from cost for PaymentMethod::Degressive: introduced
	for Valser Alm (location: Fane).
2024-07-30 15:37:28 +02:00
7536f89d75 compute_duration_for_parking_ticket():
read prepaid-setting from tariff-file, if possible.
2024-07-30 15:32:58 +02:00
9a6b2b195d get_minimal_parking_price(): compute this price dynamically according to settings
in the tariff-file. Introduced for Fuchs (500) for Valser Alm (Location: Fane)
2024-07-30 15:29:47 +02:00
7233bc55c2 test for valser alm (fane) 2024-07-30 15:24:52 +02:00
8fff7a76f6
Merge branch 'kleipeda-experimental' of /home/siegert/atbfs01entwicklung/Elektronik/PTU/git_bare_repos/libmobilisis-calc into kleipeda-experimental 2024-07-30 10:02:57 +02:00
52b7c2390a Minor: introduce using-typedef for Duration 2024-07-29 17:33:49 +02:00
894e23332f compute option index using permit type. 2024-07-29 17:32:15 +02:00
fbc255a6f2 Fix: compute_next_time_step(): removed check for product ids. 2024-07-29 17:31:33 +02:00
24ab01695d GetPriceForTimeStep(): remove default parameter. 2024-07-29 17:28:27 +02:00
37652d3b6a Save computed pop_min_time. 2024-07-29 17:27:16 +02:00
14fd7ddd39 Preperationf for Zone3. 2024-07-29 17:26:53 +02:00
ca3c3921d4 Minor: change debug output 2024-07-29 17:26:26 +02:00
37620a06c1 added test case for bus 2024-07-29 11:30:36 +02:00
9f4affca5a Minor: removed debug output 2024-07-29 11:30:00 +02:00
4f2c33cdc2 Minor: added comments and added some debug output. 2024-07-29 11:28:07 +02:00
3cd02296b0 compute_duration_for_parking_ticket():
Fix: pass PERMIT_TYPE explicitly to correct arity of GetDurationFromCost().
2024-07-29 11:25:12 +02:00
f1493f417f get_maximal_parkingprice():
implement for SHORT_TERM_PARKING_BUS and SHORT_TERM_PARKING_PKW.
2024-07-29 11:24:05 +02:00
356e3be178 Pass PERMIT_TYPE to get_minimal_parkingtime() and get_maximal_parkingtime()
to override default parameter value.
2024-07-29 11:22:22 +02:00
31b1dd1690 ResetTimeSteps():
Check paymentOptionIndex for correct value.
2024-07-29 11:20:00 +02:00
84d807930e
Merge branch 'kleipeda-experimental' of /home/siegert/atbfs01entwicklung/Elektronik/PTU/git_bare_repos/libmobilisis-calc into kleipeda-experimental 2024-07-26 17:35:38 +02:00
dbf5b1f11d remove input correction 2024-07-26 17:34:24 +02:00
18f4e74eea
Merge branch 'kleipeda-experimental' of /home/siegert/atbfs01entwicklung/Elektronik/PTU/git_bare_repos/libmobilisis-calc into kleipeda-experimental 2024-07-26 17:05:45 +02:00
29368ea850 Remove correction 2024-07-26 17:04:33 +02:00
b84f80887e Checkin for testing 2024-07-26 17:01:44 +02:00
bfd9f3b80c
Fix: add missing parameter PermitType 2024-07-26 14:11:37 +02:00
cb69d3ca2f
Merge branch 'kleipeda-experimental' of /home/siegert/atbfs01entwicklung/Elektronik/PTU/git_bare_repos/libmobilisis-calc into kleipeda-experimental 2024-07-26 13:35:56 +02:00
4a2b15d086 Add some debug output into GetDurationForPrice(). 2024-07-26 13:34:18 +02:00
63043931c2
Merge branch 'kleipeda-experimental' of /home/siegert/atbfs01entwicklung/Elektronik/PTU/git_bare_repos/libmobilisis-calc into kleipeda-experimental 2024-07-26 13:12:56 +02:00
8dad8f00e8 GetPriceForTimeStep(): Fix: user default payment option 2024-07-26 13:11:29 +02:00
1ea03f522c
Merge branch 'kleipeda-experimental' of /home/siegert/atbfs01entwicklung/Elektronik/PTU/git_bare_repos/libmobilisis-calc into kleipeda-experimental 2024-07-26 13:01:17 +02:00
805a732c52 GetPriceForTimeStep(): add prices for computed timesteps. Return maximal
price which is still smaller or equal then (input-)price.
2024-07-26 12:53:42 +02:00
ac20a767df
Merge branch 'kleipeda-experimental' of /home/siegert/atbfs01entwicklung/Elektronik/PTU/git_bare_repos/libmobilisis-calc into kleipeda-experimental 2024-07-26 11:08:02 +02:00
b7facb9d60 checkin for tariff02.json 2024-07-26 10:59:45 +02:00
8344b04b15 Use of permitType in several places 2024-07-25 09:49:16 +02:00
b0ecef0361 Use of permitType in several places 2024-07-25 09:48:12 +02:00
003b7e8e8a getPaymentOption() functions and getPaymentOptionIndex() 2024-07-25 09:46:46 +02:00
7ef2d44fc4 Add parameter PermitType to GetCostForDuration() and GetDurationFromCost() 2024-07-25 09:45:36 +02:00
8f203184b6 Add additional parameter (PermitType) to several functions 2024-07-25 09:44:24 +02:00
0bfec6a938 Added getPaymentOptionIndex() and getPaymentOptionsForAllKeys() 2024-07-25 09:43:16 +02:00
070446d01a Updated test cases for PermitType. 2024-07-24 17:35:46 +02:00
4d7e5263ee Added parsing of pop_product_id and pop_product_name. 2024-07-24 17:34:28 +02:00
7d452c82b7 Added pop_product_id and pop_product_name 2024-07-24 17:33:53 +02:00
0a08221381 Added conversion from QString to PermitType 2024-07-24 17:33:06 +02:00
b4b2e27fe3 Removed some debug output for testing 2024-07-24 12:37:29 +02:00
2a3ff30e66 Add test cases 2024-07-24 12:34:28 +02:00
b19cfd693c Minor: add some debug output. 2024-07-24 12:34:05 +02:00
78921c8870 IMPORTANT: isParkingAllowedForWeekDay(): deactivated for testing !!! 2024-07-24 12:30:46 +02:00
e891bfc5de Only check for prepaid == never. 2024-07-24 12:23:15 +02:00
a6922976bf Minor: remove some debug output. 2024-07-24 12:22:47 +02:00
7f25c46d30 Set pun_duration_saved 2024-07-23 12:51:51 +02:00
2b30e9562f Recompute time step list (previously is was saved as an optimization) 2024-07-23 12:51:08 +02:00
eb4ef0c3b5 Allow adjustment of the step list by a tolerance of 5 minutes per step 2024-07-23 12:48:50 +02:00
da05d004dd Introduced 'pun_duration_saved': to be used when time steps have to be re-calculated. 2024-07-23 12:46:44 +02:00
abf4ef0b00 GetPriceForTimeStep():
Use special flag 'pop_accumulate_prices' to add up prices given in the
tariff json file.
2024-07-23 11:53:22 +02:00
49fb860129 Minor: fixed printing of 'cost'. 2024-07-23 11:47:48 +02:00
69edc8e898 compute_product_price(): add new Products (CAR, BUS, CAMPER). 2024-07-23 11:45:34 +02:00
40440e28d3 Read pop_accumulate_prices and pop_accumulate_durations. 2024-07-22 15:56:04 +02:00
ba8e2786fc GetTimeSteps():
updated as well for Schnals (505). Still to  be tested.
2024-07-22 15:54:36 +02:00
b5804408f4 GetDurationFromCost():
expanded. still to be tested.
2024-07-22 15:53:27 +02:00
f7be0e471a getDurationFromCost():
call
		Calculator::GetInstance().GetTimeSteps(cfg, 0, inputDate);
	for its side-effects.
	Timesteps will be used in the following calculation.
2024-07-22 15:50:36 +02:00
45694106a7 GetTimeSteps():
added default parameter 'start'; was set inside the funtion.
2024-07-22 15:48:21 +02:00
6d125c65fe Added flags
pop_accumulate_prices
	pop_accumulate_durations
to decide if values in json files should be accumulated or not.
2024-07-22 15:46:45 +02:00
1c86e1ac40 tests for schnals 2024-07-22 15:46:13 +02:00
3503306637 save experimental 2024-07-21 20:58:12 +02:00
977356040c Added changes for Schnals 2024-07-19 14:10:07 +02:00
2a89f90745 Added parsing for Interpolation, CarryOver and Prepaid-options. Has to be formatted.w 2024-07-19 14:09:04 +02:00
f2356bec55 Added new products 2024-07-19 14:04:20 +02:00
2d6ef2d158 Add prepaid and carry over option 2024-07-19 14:03:46 +02:00
e5d23d8022 Added tests for Schnals 2024-07-19 14:03:06 +02:00
02927be9c9 Added interpolation, carryover and prepaid types 2024-07-19 14:02:41 +02:00
c6d396f34b Added handling for interpolation, carry over and prepaid. 2024-07-19 14:01:27 +02:00
026c791c79 Add interpolation and operator<< 2024-07-19 14:01:00 +02:00
927164e23e Added headers for interpolation, prepaid and carryover 2024-07-19 13:59:56 +02:00
507b5d1b9c Add Interpolation, Prepaid and CarryOver structures to streamline Json-File layout. 2024-07-19 13:58:22 +02:00
c153652b3d compute_next_timestep(): allow some tolerance for first time-step 2024-07-16 16:50:11 +02:00
d7e185006f GetTimeSteps(): add sanity check 2024-07-16 16:47:26 +02:00
c3c888dc04 GetTimeSteps(): remove list as reference so compute_next_timestep)_ can change it 2024-07-16 16:46:43 +02:00
2ecaa0545f Clean up. Adding SEXTEN. 2024-07-16 16:42:39 +02:00
a849f953bd Remove some parts used for testing 2024-07-16 16:42:11 +02:00
24df8e995a remove now useless file 2024-07-16 16:41:18 +02:00
b5f818848a just save tests 2024-06-26 16:25:23 +02:00
fc94e603c5 Added Logout 2024-06-14 12:50:12 +02:00
bc00d25ded login 2024-06-14 11:54:43 +02:00
4e783ee6fd just save 2024-06-13 17:23:47 +02:00
34fbefc138 save for the weekend 2024-06-07 13:33:04 +02:00
48fccafe76 Fix: GetDurationFromCost() -> set inputDate if next valid working time-range
in on another day and break the loop iterating through next days.
2024-06-06 14:04:04 +02:00
9394625d35 Minor: show debug output only when compiled in. 2024-06-06 14:02:43 +02:00
7492e37e02 Finished test for Neuhauser/Stockerau/748 2024-06-06 14:01:01 +02:00
f0dca3917c Start test-case for Neuhauser/Stockerau/748w 2024-06-05 17:05:19 +02:00
57ccbc150a compute_duration_for_parking_ticket(): set calcState according to string
returned from tariff calculation.
2024-06-05 17:03:33 +02:00
8fa4335669 Minor: fixed typo. 2024-06-05 17:03:10 +02:00
49298a1821 Extend Calculator::GetDurationFromCost() (needed for Neuhauser/Stockerau/748). 2024-06-05 17:00:27 +02:00
6fb4d245cb Added CalcState &setStatus(QString const &desc); 2024-06-05 16:58:12 +02:00
2dc93271fd Added WORKING_DAYS_WITH_RESTRICTED_HOURS (introduced for Neuhauder/Stockerau/748) 2024-06-05 16:52:54 +02:00
5be5798681 Declared iterator-arguments as const-references to get rid of compiler
warning: parameter passing for argument multi_map changed in gcc7.1
2024-06-04 11:48:50 +02:00
1a24bc4572 Add comment about main-change(s). 2024-06-04 11:39:30 +02:00
068575f8e8 improved tests 2024-06-04 11:27:57 +02:00
e121cef17e Added: uint32_t getDailyTicketCardPrice(Configuration const *cfg, PaymentMethod methodId); 2024-06-04 11:26:36 +02:00
bdaea1106c Fix: read price for daily ticket directly from entry PaymentOptions
in tariff-file if it is not given as part of a Json-Product-Array in tariff-file.
2024-06-04 11:24:15 +02:00
bc17213597 Minor: Add/change some debug putput. 2024-06-04 11:23:35 +02:00
64b2b4bd85 Fix: Handle case if "pop_carry_over_start_time_range" and "pop_carry_over_end_time_range"
is not given in tariff file.
2024-06-04 11:19:39 +02:00
8737508839 Minor: add case for PERMIT_TYPE::TWENTY_FOUR_HOURS_TICKET (TODO). 2024-06-04 11:18:47 +02:00
02f0500eac Minor: Add some (commented-out) debug messages. 2024-06-04 11:18:00 +02:00
2d53224feb Minor: add some (commented out) debug output -> used for debugging. 2024-05-15 15:23:12 +02:00
38964ad9a8 get_minimal_parkingprice(): for PERMIT_TYPE::DAY_TICKET
call compute_product_price(cfg, permitType, start) to get
minimal price dependent on 'start' datetime.
2024-05-15 15:21:38 +02:00
d3f18f3b82 get_minimal_parkingprice(): add default parameter 'start', set to
value of QDateTime::currentDateTime();
2024-05-15 15:19:47 +02:00
1a4265372e Add tests for Pernegg an der Mur 2024-05-15 15:19:13 +02:00
eb20410849 Use paymentOptionIndex in getPaymentOptions() 2024-05-08 16:34:07 +02:00
2a492475e3 Bad Neuenahr: Zone5 tests 2024-05-07 16:21:36 +02:00
6a5272da7a Fix: Check if endTime is still on the same day. 2024-05-07 15:01:16 +02:00
4d5583df2d Handling for pop_carry_over_traget. 2024-05-07 14:59:00 +02:00
de6f263817 Add FRI/SAT/SUN with restricted hours. 2024-05-07 14:57:41 +02:00
e4ce14da3f updated some tests 2024-05-06 11:38:37 +02:00
b71c979a91 Fix: getPaymentOptionIndex() -> return 0 instead of -1
Removed exit(0)-call which was used for testing.
2024-05-06 11:36:12 +02:00
33f43fb83d Start parsing of pop_min_date_time and pop_max_date_time 2024-05-03 13:50:10 +02:00
1606a784a4 Add macro _WEEKEND_WITH_RESTRICTED_HOURS_. 2024-05-03 13:49:15 +02:00
9f2cf613e1 Add struct ATBMaxDateTime. 2024-05-03 13:48:27 +02:00
dbd9644047 Add ATBPaymentOptionType = std::multimap<int, ATBPaymentOption> 2024-05-03 13:47:28 +02:00
f8fef12b55 Zone6 for Bad neuenahr 2024-04-30 14:09:48 +02:00
1dd81d4a56 get_minimal_parkingtime(): const Configuration parameter.
Cast of const pointer necessary.

get_maximal_parkingtime(): const Configuration parameter.
2024-04-30 14:08:08 +02:00
f93cf11d23 get_minimal_parkingtime()
get_maximal_parkingtime(): made configuration parameter const.
2024-04-30 14:06:04 +02:00
9d0ac4f8ce Add TWENTY_FOUR_HOURS_TICKET. Add toString() and implement conversion
operators in therm of toString().
2024-04-30 13:51:31 +02:00
4ec5589f30 Implement getTariffProductForProductId() in terms of
getTariffProductForProductTypeName().
2024-04-30 13:49:49 +02:00
c1d5ffcf3c Implement getTariffProductForProductTypeName().
Use the type names of PERMIT_TYPE, not real indices as they can change.
2024-04-30 13:48:03 +02:00
7aded2b7fb Explicit cast due to compiler warning. 2024-04-30 13:46:59 +02:00
ed9e60a972 Declaration for getTariffProductForProductTypeName(). 2024-04-30 13:45:22 +02:00
5d35331c83 Minor: introduced TariffProductType. 2024-04-30 13:44:53 +02:00
c7623429d9 Compute end_parking_time using "netto_parking_time", which is the
current timestep.
2024-04-25 15:41:52 +02:00
b596086245 Pass paymentOptionIndex to cfg->getPaymentOptions(), which has
a default parameter of paymentOptionIndex=0.
2024-04-24 13:20:02 +02:00
24ca857b6f Fix: init m_timeSteps-vector in case its size is 0: m_timeSteps.push_back(QList<int>()).
Detected during testing.
2024-04-24 13:18:23 +02:00
ea0bcde413 Check iterator for it != cfg->TimeRange.cend(). 2024-04-24 13:16:22 +02:00
e93b08505a Minor: introduce TimeRangeType as typedef for std::multimap<int, ATBTimeRange>. 2024-04-24 13:14:04 +02:00
44efd44ede Check paymentOptionIndex for test of GALTUER. 2024-04-24 13:11:28 +02:00
9d72574106 Minor: additional loop for test of NAZ 2024-04-24 12:01:24 +02:00
d8ec41ebfc Repeated tests for KIRCHDORF. Re-added utility test_neuhauser_kirchdorf(). Found bug during testing, accessing vector of size 0. 2024-04-24 11:56:50 +02:00
f17c4f240b Minor: add tests for special days in KORNEUBURG 2024-04-24 10:52:18 +02:00
76bb1eb56a Minor: small changes for tests of SCHOENAU 2024-04-24 09:54:29 +02:00
3b813e5eff Minor: small changes for tests of PERNEGG-AN-DER-MUR 2024-04-24 09:33:57 +02:00
436f5a109b Minor: add small changes to Christoph-Reisen 2024-04-24 09:17:26 +02:00
e17e54b315 Minor: add define: _ALL_DAYS_WITH_RESTRICTED_HOURS_ 2024-04-19 14:10:47 +02:00
d07fdd8540 GetPriceForTimeStep(): use parameter paymentOptionIndex. 2024-04-19 13:33:54 +02:00
1fab458de3 Implement isParkingAllowedForWeekDay(), isParkingAllowedForSpecialDay()
and isParkingAllowed() (4 parameters) using the 2 functions.
2024-04-19 13:32:24 +02:00
1ac2ca91c5 GetCostFromDuration(): use new parameter paymentOptionIndex. 2024-04-19 13:31:01 +02:00
1852f552a3 compute_price_for_parking_ticket(): compute paymentOptionIndex.
(a tariff-file can conatin more than one payment options).
2024-04-19 13:28:35 +02:00
e2c02420f0 Add parsing for new values in helper-structures.
NOTE: unfortunately switched to Unix-File-Format.
2024-04-19 13:26:33 +02:00
1240abbbec Add test cases BAD_NEUENAHR_AHRWEILER, zone2. 2024-04-19 13:24:10 +02:00
e20eb93abf Implement SpecialDaysWorkTimeFrom() and SpecialDaysWorkTimeUntil().
Extend getBusinessHours() to include new enum-values.
Implement isDayIncluded() as switch-case on dayOfWeek.
Implement dumpBusinessHours().
2024-04-19 13:21:38 +02:00
b0e7bd91b4 Add ariff_global_defines.h. 2024-04-19 13:20:44 +02:00
0cd4424434 Add utilities
isDayIncluded(), SpecialDaysWorkTimeFrom() and specialDaysWorkTimeUntil().
2024-04-19 13:19:26 +02:00
1991853b66 Add new enum-values for business_hours. Keep the old ones for
backward-compatibility.
2024-04-19 13:18:02 +02:00
b31fcc5f4f Minor: add explicit default constructor. 2024-04-19 13:17:00 +02:00
dbe649d0e4 Add member variables
pop_carry_over_start_time_range
pop_carry_over_end_time_range:

If carry-over has been set, then provide the limits
for the carry-over: at the end of day1 (start) and
at the beginning of the next day (end).
2024-04-19 13:12:46 +02:00
dfd74a455a Add getPaymentOptionIndexIfSpecialDay().
Add isSpecialDay(), isSpecialDay((), specialDayId(),
specialDay(), isSpecialDay(), specialDayId(), specialDay(),
isDayIncluded(), isDayIncludedAsSpecialDay() and isDayIncludedAsSpecialDay().
2024-04-19 13:09:53 +02:00
10828e0708 Add private mathods isParkingAllowedForWeekDay() and isParkingAllowedForSpecialDay().
Overload isParkingAllowed().
GetCostFromDuration(): add default parameter "int paymentOptionIndex=0"
2024-04-19 13:06:37 +02:00
2dbcc7018c start header for global defines 2024-04-19 13:04:36 +02:00
18ed85430d Minor: first commit 2024-04-18 08:52:15 +02:00
b70094abb5 Extend compute_product_price() for use of PERMIT_TYPE::DAY_TICKET.
First time used for Neuhauder-Pernegg-an-der-Mur.
2024-04-16 12:10:34 +02:00
aa15d1c126 Add default-parameters to compute_product_price():
start [in]: currentDateTime(): start date-time for daily-ticket-price computation.
startProduct, endProduct: real start- and end-date/time for daily-ticket.
Used first time for Neuhauser-Pernegg-an-der-Mur (747).
2024-04-16 12:07:18 +02:00
cd159f2bbd Add case for BusinessHours::NoRestriction_24_7: used for Neuhauder-Christoph-Reisen 2024-04-16 12:05:55 +02:00
475487c2ce Minor: add utility getProductPrice() 2024-04-16 12:03:42 +02:00
8ff5b8e2b5 Added test-cases for Neuhauser-Christoph-Reisen (746) and Neuhauser-Pernegg-an-der-Mur (747) 2024-04-16 12:01:36 +02:00
b0c4ad0e2e getCurrentPaymentOptionIndex(): start implementation.
getPaymentOptions(): use new parameter paymentOptionIndex.
2024-04-12 14:31:02 +02:00
7e3347b043 GetTimeSteps(): use new parameter paymentOptionIndex 2024-04-12 14:30:04 +02:00
4e7fa83507 get_minimal_parkingtime()
get_maximal_parkingtime()
get_minimal_parkingprice()
get_maximal_parkingprice():
use new parameter paymentOptionIndex.
2024-04-12 14:27:08 +02:00
ac76f194e1 Added new constants 2024-04-12 14:26:03 +02:00
fe485b7b39 pop_business_hours as uint64_t. 2024-04-12 14:24:32 +02:00
e210224340 getPaymentOptions(): added default-parameter 'paymentOptionsIndex'
Added getCurrentPaymentOptionIndex() and isHoliday().
2024-04-12 14:22:20 +02:00
afa62183fd ResetTimeSteps(), GetTimeSteps(), GetSteps():
add parameter paymentOptionIndex (default=0)
2024-04-12 14:20:05 +02:00
f241a87dc1 get_minimal_parking_price()
get_maximal_parking_price()
get_maximal_parking_time()
get_minimal_parking_time():
	adden perameter paymentOptionIndex
2024-04-12 14:17:43 +02:00
9b1cc49d34 Minor: remove some debug output 2024-04-12 14:16:18 +02:00
449e618417 Add test-cases 2024-04-12 14:14:40 +02:00
aba38d2614 compute_price_for_parking_ticket(): add handling for PaymentMethod::Steps. 2024-04-08 13:58:24 +02:00
57d6b85f52 get_maximal_parking_price(): add handling for PaymentMethod::Steps. 2024-04-08 13:57:40 +02:00
4f9c0422fc Start test case for Bad Neuenahr 2024-04-08 13:53:29 +02:00
a5b95d71b8 CalcState: Add setStatus()/getStatus() 2024-04-08 13:52:53 +02:00
fcbc8dcdc3 Merge branch 'neuhauser-kirchdorf' of https://git.mimbach49.de/GerhardHoffmann/MOBILISIS-Calculator into neuhauser-kirchdorf 2024-03-07 08:19:26 +01:00
ed99bae725 Use Calculator::getInstance() 2024-03-07 08:18:40 +01:00
627d14204d Use paymentRate.last() instead of aymentRate.at(0) so we can enter new entries
in tariff-files to provide the prices for an hour.
2024-03-07 08:17:32 +01:00
d8a4c4eaa7
Merge branch 'neuhauser-kirchdorf' of git.mimbach49.de:GerhardHoffmann/MOBILISIS-Calculator into neuhauser-kirchdorf 2024-02-29 09:30:22 +01:00
4f45db4fde revised tests for Neuhauser/Linsinger Maschinenbau (744) 2024-02-28 12:06:43 +01:00
a744a1ebb3 compute_product_price(): add handling for FOOD_STAMP 2024-02-28 12:06:02 +01:00
df16bd7f9c GetDailyTicketPrice(): add case for FOOD_STAMP (not implemented) 2024-02-28 12:05:14 +01:00
b751ba339e Add permit type FOOD_STAMP 2024-02-28 12:03:13 +01:00
588a88455b
CalcState: add toString() method 2024-02-28 11:31:28 +01:00
92bfdced6a
Merge branch 'neuhauser-kirchdorf' of git.mimbach49.de:GerhardHoffmann/MOBILISIS-Calculator into neuhauser-kirchdorf 2024-02-28 10:04:09 +01:00
8bbec596c9 Check for 08:00 <= currentTime <= 20:00 removed:
assumption is prepaid.
2024-02-28 09:58:00 +01:00
87b14ee3f8 Added check for NEUHAUSER_NORDISCHES_AUSBILDUNGSZENTRUM:
08:00 <= currentTime <= 20:00.
2024-02-28 09:26:51 +01:00
3ad2c77467 Adapted tests for NEUHAUSER_NORDISCHES_AUSBILDUNGSZENTRUM 2024-02-28 09:26:05 +01:00
493d94aaa1 Add re-check 2024-02-27 17:30:15 +01:00
7831329b11 kirchdorf: getDurationFromCost(): to be tested 2024-02-27 17:11:00 +01:00
abbbd06f93 GetCostFromDuration(): re-implement cpmputation for paymentMethod==progressive
(e.g. neuhauser/kirchdorf (743))
2024-02-27 12:25:13 +01:00
ac6e45a913 test cases for neuhauser-kirchdorf 2024-02-27 12:23:52 +01:00
b741d2e312 test 2024-02-26 16:57:37 +01:00
6756aa5b88 Added zone3 - zone6 to szeged 2024-02-24 11:07:04 +01:00
7845ab8077 testing: started with zone 3 for szeged 2024-02-23 14:20:16 +01:00
cc222c298a Add test case for szeged: zone 2 2024-02-23 13:54:31 +01:00
eb645273cc Add declaration for get_maximal_parkingprice() 2024-02-23 13:17:03 +01:00
bd1bdf8a8c Implement compute_procuct_price() 2024-02-22 16:38:41 +01:00
6d18ce4caa GetDailyTicketPrice(): improve for projects which have not defined a daily ticket in their tariff-files. 2024-02-22 16:37:11 +01:00
e980d8c451 Implement
std::optional<QVector<ATBTariffProduct>> getTariffProductForAllKeys() const;
    std::optional<QVector<ATBTariffProduct>> getTariffProductForProductId(int id) const;
    std::optional<QVector<ATBTariffProduct>> getTariffProductForProductId(PermitType permitType) const;
2024-02-22 16:34:57 +01:00
afb0e20dd2 Implement parsing of "Product" and adding into TariffProduct. 2024-02-22 16:33:19 +01:00
39ab08a5b7 Add ProductType 2024-02-22 16:32:16 +01:00
c4c0e2fd77 Added TariffProduct including necessary functions to retrieve product infos from tariff-file 2024-02-22 16:31:51 +01:00
7a5487aa41 Add compute_product_price 2024-02-22 16:27:52 +01:00
a8c1caf611 Add tariff_product.h and tariff_permit_type.h 2024-02-22 16:26:09 +01:00
a22145002c Add test case for NAZ 2024-02-22 16:25:30 +01:00
7b7dd6d103 Add representations for PERMIT_TYPE and Product 2024-02-22 16:25:09 +01:00
1c801f1053 re-tested neuhauser-linisinger-maschinenbau 2024-02-22 09:44:35 +01:00
56fc95e33c GetDurationFromCost(): reverted, as there is a new default parameter (prepaid)
in compute_price_for_parming_ticket().
2024-02-22 09:43:04 +01:00
c0f81f174a compute_price_for_parking_ticket(): added parameter bool prepaid. Set to true as default. 2024-02-22 09:42:02 +01:00
6ba3963f25 compute_price_for_parking_ticket(): added default parameter prepaid=true.
(Needed e.g. for Neuhauser/Linsinger Maschinenbau (741)
2024-02-22 09:40:27 +01:00
1a350c0aeb GetDurationFromCost(): aded section if prepaid is not set.
E.g. for Linsinger Maschinenbau (Neuhauser, 741): here, the buying
of food stamps is obviously only possible at certain times.
2024-02-22 09:31:41 +01:00
15801be88e re-tested neuhauser-naz 2024-02-22 09:30:15 +01:00
20e146d3c9 re-tested neuhauser-naz 2024-02-22 09:10:26 +01:00
30768c6931 prepared test case for neuhauser-kirchdorf 2024-02-22 08:02:55 +01:00
7933c826e6 Synced GetDurationFromCost() with GetCostFromDuration() 2024-02-21 14:53:06 +01:00
9d5ddfc328 GetCostFromDuration(): fixed moving from time range 8:00-12:00 -> 14:00-18:00. 2024-02-21 14:20:51 +01:00
102607b71f GetTimeSteps(): adapt for progressive tariff (e.g. neuhauser/kirchdorf).
Compute timesteps according to tariff01.json file.
2024-02-21 11:16:44 +01:00
81d515eb7f GetCostFromDuration(): set endtime to start in case cost==0. 2024-02-21 11:13:53 +01:00
ce61e5d3b2 compute_next_timestep(): use fpr PaymentMenthod::Progressive
same code as for PaymentMethod::Steps, as GetTimeSteps() inside
the Calculator class has been adapted accordingly.
2024-02-21 11:11:09 +01:00
b6a0f5e8af tests for neuhauser/kirchdorf 2024-02-21 11:08:49 +01:00
e0223b50f9 Added helper getTimeRangeStep() (useful for progressive tariff as for neuhauser/kirchdorf (743) 2024-02-21 09:31:13 +01:00
690267c388 get_maximal_parkingprice(): in case of progressive tariff, read maximal parking time
directly form tariff-file as there is not price per hour.
2024-02-20 15:47:02 +01:00
9c19414e5a GetDurationFromCost(): add some sanity checks for cost. Check if cost < minParkingPrice.
Cut cost internally to maxParkingPrice if cost > maxParkingPrice.
2024-02-20 13:47:45 +01:00
50 changed files with 21964 additions and 1534 deletions

1
\ Normal file

@ -0,0 +1 @@
return std::make_pair(CalcState(CalcState::State::OVERPAID), dt);

@ -0,0 +1,83 @@
#ifndef ATB_TIME_H_INCLUDED
#define ATB_TIME_H_INCLUDED
#include <QDateTime>
class ATBTime {
static QDateTime const m_end;
mutable QDateTime m_time;
public:
explicit ATBTime();
explicit ATBTime(int h, int m, int s = 0, int ms = 0);
explicit ATBTime(QString const &time);
explicit ATBTime(QTime const &time);
explicit ATBTime(ATBTime const &atbTime) {
m_time = atbTime.m_time;
}
ATBTime &operator=(ATBTime && atbTime) {
m_time = std::move(atbTime.m_time);
return *this;
}
ATBTime &operator=(ATBTime const &atbTime) {
m_time = atbTime.m_time;
return *this;
}
int hour() const { return m_time.time().hour(); }
int minute() const { return m_time.time().minute(); }
int second() const { return m_time.time().second(); }
int msec() const { return m_time.time().msec(); }
int secsTo(QString const &t) const {
if (t == "24:00:00") {
return m_time.secsTo(m_end);
}
return m_time.time().secsTo(QTime::fromString(t, Qt::ISODate));
}
int msecsTo(QTime t) const { return m_time.time().msecsTo(t); }
bool setHMS(int h, int m, int s, int ms = 0);
bool isNull() const { return m_time.time().isNull(); }
bool isValid() const { return m_time.time().isValid(); }
QTime addMSecs(int ms) const;
QTime addMSecs(int ms);
QTime addSecs(int s) const;
QTime addSecs(int s);
int msecsSinceStartOfDay() const;
QString toString(Qt::DateFormat format = Qt::TextDate) const;
static bool isValid(int h, int m, int s, int ms = 0);
static QTime currentTime() { return QDateTime::currentDateTime().time(); }
static constexpr QTime fromMSecsSinceStartOfDay(int msecs);
static QTime fromString(QString const &string, Qt::DateFormat format = Qt::TextDate);
static QTime fromString(QString const &string, const QString &format);
friend bool operator!=(const ATBTime &lhs, const ATBTime &rhs) noexcept;
friend bool operator<(const ATBTime &lhs, const ATBTime &rhs) noexcept;
friend bool operator<=(const ATBTime &lhs, const ATBTime &rhs) noexcept;
friend bool operator>=(const ATBTime &lhs, const ATBTime &rhs) noexcept;
friend bool operator<(const ATBTime &lhs, const ATBTime &rhs) noexcept;
friend bool operator>(const ATBTime &lhs, const ATBTime &rhs) noexcept;
friend bool operator==(const ATBTime &lhs, const ATBTime &rhs) noexcept;
friend QDataStream &operator<<(QDataStream &out, ATBTime const &time);
friend QDebug &operator<<(QDebug &out, ATBTime const &time);
friend QDataStream &operator>>(QDataStream &in, ATBTime &time);
};
#endif // ATB_TIME_H_INCLUDED

@ -18,6 +18,8 @@
#define CALCULATE_LIBRARY_API #define CALCULATE_LIBRARY_API
#endif #endif
#include "tariff_permit_type.h"
class Configuration; class Configuration;
typedef Configuration parking_tariff_t; typedef Configuration parking_tariff_t;
@ -39,32 +41,39 @@ struct CALCULATE_LIBRARY_API price_t {
} }
}; };
enum class PERMIT_TYPE : quint8 {
SHORT_TERM_PARKING,
DAY_TICKET,
SZEGED_START,
SZEGED_STOP,
DAY_TICKET_ADULT,
DAY_TICKET_TEEN,
DAY_TICKET_CHILD,
INVALID
};
struct CALCULATE_LIBRARY_API CalcState { struct CALCULATE_LIBRARY_API CalcState {
static QString const SUCCESS;
static QString const ERROR_PARSING_ZONE_NR;
static QString const ERROR_LOADING_TARIFF;
static QString const ERROR_PARSING_TARIFF;
static QString const NEGATIVE_PARKING_TIME;
static QString const INVALID_START_DATE;
static QString const WRONG_PARAM_VALUES;
static QString const WRONG_ISO_TIME_FORMAT;
static QString const ABOVE_MAX_PARKING_TIME;
static QString const BELOW_MIN_PARKING_TIME;
static QString const BELOW_MIN_PARKING_PRICE;
static QString const ABOVE_MAX_PARKING_PRICE;
static QString const OVERPAID;
static QString const OUTSIDE_ALLOWED_PARKING_TIME;
static QString const SUCCESS_MAXPRICE;
enum class State : uint8_t { enum class State : uint8_t {
SUCCESS, SUCCESS,
ERROR_PARSING_ZONE_NR, ERROR_PARSING_ZONE_NR,
ERROR_LOADING_TARIFF, ERROR_LOADING_TARIFF,
ERROR_PARSING_TARIFF, ERROR_PARSING_TARIFF,
NEGATIVE_PARING_TIME, NEGATIVE_PARKING_TIME,
INVALID_START_DATE, INVALID_START_DATE,
WRONG_PARAM_VALUES, WRONG_PARAM_VALUES,
WRONG_ISO_TIME_FORMAT, WRONG_ISO_TIME_FORMAT,
ABOVE_MAX_PARKING_TIME, ABOVE_MAX_PARKING_TIME,
BELOW_MIN_PARKING_TIME, BELOW_MIN_PARKING_TIME,
BELOW_MIN_PARKING_PRICE, BELOW_MIN_PARKING_PRICE,
ABOVE_MAX_PARKING_PRICE,
OVERPAID, OVERPAID,
OUTSIDE_ALLOWED_PARKING_TIME OUTSIDE_ALLOWED_PARKING_TIME,
SUCCESS_MAXPRICE
}; };
State m_status; State m_status;
@ -81,9 +90,9 @@ struct CALCULATE_LIBRARY_API CalcState {
, m_desc(desc) { , m_desc(desc) {
} }
explicit CalcState(State state, QString desc = "", explicit CalcState(State state, QString desc,
QTime const &from = QTime(), QTime const &from,
QTime const &until = QTime()) QTime const &until)
: m_status(state) : m_status(state)
, m_desc(desc) , m_desc(desc)
, m_allowedTimeRange(from, until) { , m_allowedTimeRange(from, until) {
@ -93,53 +102,166 @@ struct CALCULATE_LIBRARY_API CalcState {
return (m_status == State::SUCCESS); return (m_status == State::SUCCESS);
} }
QString toString() {
QString s;
switch (m_status) {
case State::SUCCESS:
s = CalcState::SUCCESS;
break;
case State::SUCCESS_MAXPRICE:
s = CalcState::SUCCESS_MAXPRICE;
break;
case State::ERROR_PARSING_ZONE_NR:
s = CalcState::ERROR_PARSING_ZONE_NR;
break;
case State::ERROR_LOADING_TARIFF:
s = CalcState::ERROR_LOADING_TARIFF;
break;
case State::ERROR_PARSING_TARIFF:
s = CalcState::ERROR_PARSING_TARIFF;
break;
case State::NEGATIVE_PARKING_TIME:
s = CalcState::NEGATIVE_PARKING_TIME;
break;
case State::ABOVE_MAX_PARKING_TIME:
s = CalcState::ABOVE_MAX_PARKING_TIME;
break;
case State::WRONG_PARAM_VALUES:
s = CalcState::WRONG_PARAM_VALUES;
break;
case State::BELOW_MIN_PARKING_TIME:
s = CalcState::BELOW_MIN_PARKING_TIME;
break;
case State::BELOW_MIN_PARKING_PRICE:
s = CalcState::BELOW_MIN_PARKING_PRICE;
break;
case State::OVERPAID:
s = CalcState::OVERPAID;
break;
case State::INVALID_START_DATE:
s = CalcState::INVALID_START_DATE;
break;
case State::WRONG_ISO_TIME_FORMAT:
s = CalcState::WRONG_ISO_TIME_FORMAT;
break;
case State::OUTSIDE_ALLOWED_PARKING_TIME:
s = CalcState::OUTSIDE_ALLOWED_PARKING_TIME;
break;
case State::ABOVE_MAX_PARKING_PRICE:
s = CalcState::ABOVE_MAX_PARKING_TIME;
break;
}
if (m_desc.size() > 0) {
return s + ":" + m_desc;
}
return s;
}
explicit operator QString () const noexcept { explicit operator QString () const noexcept {
QString s; QString s;
switch (m_status) { switch (m_status) {
case State::SUCCESS: case State::SUCCESS:
s = "SUCCESS"; s = CalcState::SUCCESS;
break;
case State::SUCCESS_MAXPRICE:
s = CalcState::SUCCESS_MAXPRICE;
break; break;
case State::ERROR_PARSING_ZONE_NR: case State::ERROR_PARSING_ZONE_NR:
s = "ERROR_PARSING_ZONE_NR"; s = CalcState::ERROR_PARSING_ZONE_NR;
break; break;
case State::ERROR_LOADING_TARIFF: case State::ERROR_LOADING_TARIFF:
s = "ERROR_LOADING_TARIFF"; s = CalcState::ERROR_LOADING_TARIFF;
break; break;
case State::ERROR_PARSING_TARIFF: case State::ERROR_PARSING_TARIFF:
s = "ERROR_PARSING_TARIFF"; s = CalcState::ERROR_PARSING_TARIFF;
break; break;
case State::NEGATIVE_PARING_TIME: case State::NEGATIVE_PARKING_TIME:
s = "NEGATIVE_PARKING_TIME"; s = CalcState::NEGATIVE_PARKING_TIME;
break; break;
case State::ABOVE_MAX_PARKING_TIME: case State::ABOVE_MAX_PARKING_TIME:
s = "ABOVE_MAX_PARKING_TIME"; s = CalcState::ABOVE_MAX_PARKING_TIME;
break; break;
case State::WRONG_PARAM_VALUES: case State::WRONG_PARAM_VALUES:
s = "WRONG_PARAM_VALUES"; s = CalcState::WRONG_PARAM_VALUES;
break; break;
case State::BELOW_MIN_PARKING_TIME: case State::BELOW_MIN_PARKING_TIME:
s = "BELOW_MIN_PARKING_TIME"; s = CalcState::BELOW_MIN_PARKING_TIME;
break; break;
case State::BELOW_MIN_PARKING_PRICE: case State::BELOW_MIN_PARKING_PRICE:
s = "BELOW_MIN_PARKING_PRICE"; s = CalcState::BELOW_MIN_PARKING_PRICE;
break; break;
case State::OVERPAID: case State::OVERPAID:
s = "OVERPAID"; s = CalcState::OVERPAID;
break; break;
case State::INVALID_START_DATE: case State::INVALID_START_DATE:
s = "INVALID_START_DATE"; s = CalcState::INVALID_START_DATE;
break; break;
case State::WRONG_ISO_TIME_FORMAT: case State::WRONG_ISO_TIME_FORMAT:
s = "WRONG_ISO_TIME_FORMAT"; s = CalcState::WRONG_ISO_TIME_FORMAT;
break; break;
case State::OUTSIDE_ALLOWED_PARKING_TIME: case State::OUTSIDE_ALLOWED_PARKING_TIME:
s = "OUTSIDE_ALLOWED_PARKING_TIME"; s = CalcState::OUTSIDE_ALLOWED_PARKING_TIME;
break;
case State::ABOVE_MAX_PARKING_PRICE:
s = CalcState::ABOVE_MAX_PARKING_TIME;
break;
} }
return s + ":" + m_desc; return s + ":" + m_desc;
} }
CalcState &set(State s) { m_status = s; return *this; } CalcState &set(State s) { m_status = s; return *this; }
CalcState &setDesc(QString s) { m_desc = s; return *this; } CalcState &setStatus(State s) { return set(s); }
CalcState &setStatus(QString const &desc) {
if (desc == SUCCESS) {
m_status = State::SUCCESS;
} else
if (desc == SUCCESS_MAXPRICE) {
m_status = State::SUCCESS_MAXPRICE;
}
if (desc == ERROR_PARSING_ZONE_NR) {
m_status = State::ERROR_PARSING_ZONE_NR;
} else
if (desc == ERROR_LOADING_TARIFF) {
m_status = State::SUCCESS;
} else
if (desc == ERROR_PARSING_TARIFF) {
m_status = State::ERROR_LOADING_TARIFF;
} else
if (desc == NEGATIVE_PARKING_TIME) {
m_status = State::NEGATIVE_PARKING_TIME;
} else
if (desc == INVALID_START_DATE) {
m_status = State::INVALID_START_DATE;
} else
if (desc == WRONG_PARAM_VALUES) {
m_status = State::WRONG_PARAM_VALUES;
} else
if (desc == WRONG_ISO_TIME_FORMAT) {
m_status = State::WRONG_ISO_TIME_FORMAT;
} else
if (desc == ABOVE_MAX_PARKING_TIME) {
m_status = State::ABOVE_MAX_PARKING_TIME;
} else
if (desc == BELOW_MIN_PARKING_TIME) {
m_status = State::BELOW_MIN_PARKING_TIME;
} else
if (desc == BELOW_MIN_PARKING_PRICE) {
m_status = State::BELOW_MIN_PARKING_PRICE;
} else
if (desc == OVERPAID) {
m_status = State::OVERPAID;
} else
if (desc == OUTSIDE_ALLOWED_PARKING_TIME) {
m_status = State::OUTSIDE_ALLOWED_PARKING_TIME;
} else
if (desc == ABOVE_MAX_PARKING_PRICE) {
m_status = State::ABOVE_MAX_PARKING_PRICE;
}
return *this;
}
State getStatus() const { return m_status; }
CalcState &setDesc(QString const &s) { m_desc = s; return *this; }
void setAllowedTimeRange(QTime const &from, QTime const &until) { void setAllowedTimeRange(QTime const &from, QTime const &until) {
m_allowedTimeRange.setTimeRange(from, until); m_allowedTimeRange.setTimeRange(from, until);
@ -155,43 +277,69 @@ CalcState CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff,
void CALCULATE_LIBRARY_API free_tariff(parking_tariff_t *tariff); void CALCULATE_LIBRARY_API free_tariff(parking_tariff_t *tariff);
int CALCULATE_LIBRARY_API get_zone_nr(int zone = -1); int CALCULATE_LIBRARY_API get_zone_nr(int zone = -1);
int CALCULATE_LIBRARY_API compute_next_timestep(parking_tariff_t *tariff, int currentTimeMinutes, int UpDown); int CALCULATE_LIBRARY_API compute_next_timestep(parking_tariff_t *tariff, int currentTimeMinutes,
int UpDown, PermitType const &permitType);
QList<int> CALCULATE_LIBRARY_API get_time_steps(Configuration *cfg); QList<int> CALCULATE_LIBRARY_API get_time_steps(Configuration *cfg);
int CALCULATE_LIBRARY_API get_minimal_parkingtime(Configuration *cfg, PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING);
int CALCULATE_LIBRARY_API get_maximal_parkingtime(Configuration *cfg, PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING); int CALCULATE_LIBRARY_API get_minimal_parkingtime(Configuration const *cfg,
int CALCULATE_LIBRARY_API get_minimal_parkingprice(Configuration *cfg, PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING); PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING,
int CALCULATE_LIBRARY_API get_maximal_parkingprice(Configuration *cfg, PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING); int paymentOptionIndex=0);
int CALCULATE_LIBRARY_API get_maximal_parkingtime(Configuration const *cfg,
PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING,
int paymentOptionIndex=0);
int CALCULATE_LIBRARY_API get_minimal_parkingprice(Configuration *cfg,
PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING,
int paymentOptionIndex = 0,
QDateTime const &start = QDateTime::currentDateTime());
int CALCULATE_LIBRARY_API get_maximal_parkingprice(Configuration *cfg,
PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING,
int paymentOptionIndex=0);
int CALCULATE_LIBRARY_API compute_product_price(Configuration const *cfg,
PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING,
QDateTime const &start = QDateTime::currentDateTime(),
QDateTime *productStart = nullptr,
QDateTime *productEnd = nullptr);
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket( // deprecated CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket( // deprecated
parking_tariff_t *tariff, parking_tariff_t *tariff,
time_t start_parking_time, time_t start_parking_time,
time_t end_parking_time, time_t end_parking_time,
struct price_t *price); struct price_t *price,
PermitType permitType);
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket( CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
parking_tariff_t *tariff, parking_tariff_t *tariff,
QDateTime &start_parking_time, QDateTime &start_parking_time,
int netto_parking_time, int netto_parking_time,
QDateTime &end_parking_time, // return value QDateTime &end_parking_time, // return value
struct price_t *price); // return value struct price_t *price, // return value
PermitType permitType,
bool prepaid = true);
CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket( // deprecated CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket( // deprecated
parking_tariff_t *tariff, parking_tariff_t *tariff,
time_t start_parking_time, time_t start_parking_time,
double cost, double cost,
QString &duration); QString &duration,
PermitType permitType);
CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket( CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket(
parking_tariff_t *tariff, parking_tariff_t *tariff,
QDateTime const &start_parking_time, QDateTime const &start_parking_time,
double cost, double cost,
QDateTime &ticketEndTime); // return value QDateTime &ticketEndTime,
PermitType permitType); // return value
CalcState CALCULATE_LIBRARY_API compute_duration_for_daily_ticket( CalcState CALCULATE_LIBRARY_API compute_duration_for_daily_ticket(
parking_tariff_t *tariff, parking_tariff_t *tariff,
QDateTime const &start_parking_time, QDateTime const &start_parking_time,
QDateTime &ticketEndTime); QDateTime &ticketEndTime,
PermitType permitType);
CalcState CALCULATE_LIBRARY_API compute_price_for_daily_ticket( CalcState CALCULATE_LIBRARY_API compute_price_for_daily_ticket(
parking_tariff_t *tariff, parking_tariff_t *tariff,

@ -3,6 +3,7 @@
#include <iostream> #include <iostream>
#include <optional> #include <optional>
#include <utility>
#include "configuration.h" #include "configuration.h"
#include "calculate_price.h" #include "calculate_price.h"
@ -14,11 +15,28 @@
using namespace std; using namespace std;
class Calculator { class Calculator {
mutable QList<int> m_timeSteps; mutable QVector<QList<int>> m_timeSteps;
mutable QList<int> m_priceSteps; mutable QList<int> m_priceSteps;
CalcState isParkingAllowedForWeekDay(Configuration const *cfg,
QDateTime const &start,
int netto_parking_time,
int paymentOptionIndex);
CalcState isParkingAllowedForSpecialDay(Configuration const *cfg,
QDateTime const &start,
int netto_parking_time,
int paymentOptionIndex);
struct State {
bool m_timeLimitReached;
uint32_t m_costAtTimeLimit;
} m_state;
protected: protected:
explicit Calculator() = default; explicit Calculator() {
m_state.m_timeLimitReached = false;
m_state.m_costAtTimeLimit = ~0;
}
public: public:
Calculator(Calculator const &other) = delete; Calculator(Calculator const &other) = delete;
@ -29,13 +47,34 @@ public:
return c; return c;
} }
void ResetTimeSteps() { m_timeSteps.clear(); } bool timeLimitReached() const { return m_state.m_timeLimitReached; }
QList<int> timeSteps() const { return m_timeSteps; } void setTimeLimitReached(bool timeLimitReached) { m_state.m_timeLimitReached = timeLimitReached; }
bool costAtTimeLimit() const { return m_state.m_costAtTimeLimit; }
void setCostAtTimeLimit(uint32_t cost) { if (m_state.m_costAtTimeLimit > cost) m_state.m_costAtTimeLimit = cost; }
void resetCostAtTimeLimit() { m_state.m_costAtTimeLimit = ~0; }
void ResetTimeSteps(int paymentOptionIndex) {
if (m_timeSteps.size() > 0 && paymentOptionIndex < m_timeSteps.size()) {
m_timeSteps[paymentOptionIndex].clear();
}
}
QList<int> timeSteps(int paymentOptionIndex=0) const {
if (m_timeSteps.size() > 0 && paymentOptionIndex < m_timeSteps.size()) {
return m_timeSteps[paymentOptionIndex];
}
return QList<int>();
}
void ResetPriceSteps() { m_priceSteps.clear(); } void ResetPriceSteps() { m_priceSteps.clear(); }
QList<int> priceSteps() const { return m_priceSteps; } QList<int> priceSteps() const { return m_priceSteps; }
CalcState isParkingAllowed(Configuration const *cfg, QDateTime const &start); CalcState isParkingAllowed(Configuration const *cfg,
QDateTime const &start);
CalcState isParkingAllowed(Configuration const *cfg,
QDateTime const &start,
int netto_parking_time,
int paymentOptionIndex);
/// <summary> /// <summary>
/// Gets duration in seconds from cost /// Gets duration in seconds from cost
@ -45,7 +84,9 @@ public:
/// <param name="start_datetime">Date/time of payment to be conducted in ISO8601 format (e.g. 2022-12-25T08:00:00Z)</param> /// <param name="start_datetime">Date/time of payment to be conducted in ISO8601 format (e.g. 2022-12-25T08:00:00Z)</param>
/// <param name="price"></param> /// <param name="price"></param>
/// <returns>Returns duration in seconds (data type: double)</returns> /// <returns>Returns duration in seconds (data type: double)</returns>
std::string GetDurationFromCost(Configuration* cfg, uint8_t vehicle_type, char const* start_datetime, double price, bool nextDay = false, bool prepaid = false); std::pair<std::string, QDateTime>
GetDurationFromCost(Configuration* cfg, uint8_t vehicle_type, char const* start_datetime, double price,
PermitType permitType, bool nextDay = false, bool prepaid = false);
/// <summary> /// <summary>
/// Gets cost from duration in seconds /// Gets cost from duration in seconds
@ -56,7 +97,11 @@ public:
/// <param name="end_datetime">Date/time of park end to be conducted in ISO8601 format (e.g. 2022-12-25T08:00:00Z) </param> /// <param name="end_datetime">Date/time of park end to be conducted in ISO8601 format (e.g. 2022-12-25T08:00:00Z) </param>
/// <param name="durationMin">Duration of parking in minutes</param> /// <param name="durationMin">Duration of parking in minutes</param>
/// <returns>Returns cost (data type: double)</returns> /// <returns>Returns cost (data type: double)</returns>
double GetCostFromDuration(Configuration* cfg, uint8_t vehicle_type, QDateTime &start_datetime, QDateTime & end_datetime, int durationMin, bool nextDay = false, bool prepaid = false); double GetCostFromDuration(Configuration* cfg, uint8_t vehicle_type, QDateTime &start_datetime, QDateTime & end_datetime, int durationMin,
PermitType permitType, bool nextDay = false, bool prepaid = false);
std::pair<CalcState, QDateTime> ComputeDurationFromCost(Configuration *cfg, QDateTime const &startDatetimePassed, int cost);
std::pair<CalcState, std::optional<int>> ComputeCostFromDuration(Configuration *cfg, QDateTime const &startDatetime, QDateTime &endDatetime, int nettoParkingTime);
// Daily ticket // Daily ticket
QDateTime GetDailyTicketDuration(Configuration* cfg, const QDateTime start_datetime, uint8_t payment_option, bool carry_over); QDateTime GetDailyTicketDuration(Configuration* cfg, const QDateTime start_datetime, uint8_t payment_option, bool carry_over);
@ -66,8 +111,10 @@ public:
// helper function to find time steps for a tariff with PaymentMethod::Steps // helper function to find time steps for a tariff with PaymentMethod::Steps
// (e.g. Schoenau/Koenigsee) // (e.g. Schoenau/Koenigsee)
// //
QList<int> GetTimeSteps(Configuration *cfg) const; QList<int> &GetTimeSteps(Configuration *cfg, int paymentOptionIndex=0, QDateTime const &start = QDateTime::currentDateTime()) const;
QList<int> GetSteps(Configuration *cfg) const { return GetTimeSteps(cfg); } QList<int> GetSteps(Configuration *cfg, int paymentOptionIndex=0, QDateTime const &start = QDateTime::currentDateTime()) const {
return GetTimeSteps(cfg, paymentOptionIndex, start);
}
QList<int> GetPriceSteps(Configuration *cfg) const; QList<int> GetPriceSteps(Configuration *cfg) const;
@ -87,8 +134,8 @@ public:
// testing public: // testing public:
// Introduced for PaymentMethod::Steps (e.g. Schoenau) // Introduced for PaymentMethod::Steps (e.g. Schoenau)
// For tariff of following structure: only steps, no special days, nonstop. // For tariff of following structure: only steps, no special days, nonstop.
uint32_t GetCostFromDuration(Configuration *cfg, QDateTime const &start, quint64 durationMinutes) const; uint32_t GetCostFromDuration(Configuration *cfg, QDateTime const &start, quint64 durationMinutes, int paymentOptionIndex=0) const;
uint32_t GetCostFromDuration(Configuration *cfg, QDateTime const &start, QDateTime const &end) const; uint32_t GetCostFromDuration(Configuration *cfg, QDateTime const &start, QDateTime const &end, int paymentOptionIndex=0) const;
private: private:
Ticket private_GetCostFromDuration(Configuration const* cfg, Ticket private_GetCostFromDuration(Configuration const* cfg,
@ -104,10 +151,10 @@ private:
int durationMinutes); int durationMinutes);
// //
uint32_t GetPriceForTimeStep(Configuration *cfg, int timeStep) const; uint32_t GetPriceForTimeStep(Configuration *cfg, int timeStep, int paymentOptionIndex) const;
uint32_t GetPriceForStep(Configuration *cfg, int step) const { //uint32_t GetPriceForStep(Configuration *cfg, int step) const {
return GetPriceForTimeStep(cfg, step); // return GetPriceForTimeStep(cfg, step, 0);
} //}
uint32_t GetDurationForPrice(Configuration *cfg, int price) const; uint32_t GetDurationForPrice(Configuration *cfg, int price) const;
uint32_t GetStepForPrice(Configuration *cfg, int price) const { uint32_t GetStepForPrice(Configuration *cfg, int price) const {
return GetDurationForPrice(cfg, price); return GetDurationForPrice(cfg, price);

@ -24,6 +24,13 @@
#include "tariff_daily_ticket.h" #include "tariff_daily_ticket.h"
#include "time_range_header.h" #include "time_range_header.h"
#include "tariff_timestep_config.h" #include "tariff_timestep_config.h"
#include "tariff_product.h"
#include "tariff_interpolation.h"
#include "tariff_prepaid.h"
#include "tariff_carryover.h"
#include "tariff_permit_type.h"
#include "tariff_service.h"
#include "tariff_out_of_service.h"
#include <QVector> #include <QVector>
#include <optional> #include <optional>
@ -31,28 +38,51 @@
using namespace std; using namespace std;
using namespace rapidjson; using namespace rapidjson;
class Calculator; class Calculator;
class Configuration class Configuration
{ {
public: public:
using SpecialDaysType = std::multimap<int, ATBSpecialDays>;
using SpecialDaysWorktimeType = std::multimap<int, ATBSpecialDaysWorktime>;
using TimeRangeType = std::multimap<int, ATBTimeRange>;
using TariffProductType = std::multimap<int, ATBTariffProduct>;
using ATBPaymentOptionType = std::multimap<int, ATBPaymentOption>;
using TariffInterpolationType = std::multimap<int, ATBInterpolation>;
using TariffPrepaidType = std::multimap<int, ATBPrepaid>;
using TariffCarryOverType = std::multimap<int, ATBCarryOver>;
using TariffDurationType = std::multimap<int, ATBDuration>;
using TariffServiceType = std::multimap<int, ATBTariffService>;
using TariffOutOfServiceType = std::multimap<int, ATBTariffOutOfService>;
using ATBTariffPrepaidType = std::multimap<int, ATBTariffPrepaid>;
using ATBTariffCarryOverType = std::multimap<int, ATBTariffCarryOver>;
ATBProject project; ATBProject project;
ATBCurrency Currency; ATBCurrency Currency;
ATBDuration duration; ATBDuration duration;
multimap<int, ATBDuration> Duration; TariffDurationType Duration;
multimap<int, ATBPaymentMethod> PaymentMethod; multimap<int, ATBPaymentMethod> PaymentMethod;
multimap<int, ATBPaymentRate> PaymentRate; multimap<int, ATBPaymentRate> PaymentRate;
multimap<int, ATBSpecialDaysWorktime> SpecialDaysWorktime; SpecialDaysWorktimeType SpecialDaysWorktime;
multimap<int, ATBSpecialDays> SpecialDays; SpecialDaysType SpecialDays;
multimap<int, ATBWeekDays> WeekDays; multimap<Qt::DayOfWeek, ATBWeekDay> WeekDays;
multimap<int, ATBPeriodYear> YearPeriod; multimap<int, ATBPeriodYear> YearPeriod;
multimap<int, ATBWeekDaysWorktime> WeekDaysWorktime; multimap<int, ATBWeekDaysWorktime> WeekDaysWorktime;
multimap<int, ATBPaymentOption> PaymentOption; ATBPaymentOptionType PaymentOption;
multimap<int, ATBDailyTicket> DailyTicket; multimap<int, ATBDailyTicket> DailyTicket;
multimap<int, ATBTimeRange> TimeRange; TimeRangeType TimeRange;
multimap<int, ATBTimeStepConfig> TimeStepConfig; multimap<int, ATBTimeStepConfig> TimeStepConfig;
multimap<int, ATBTimeBase> TimeBase; multimap<int, ATBTimeBase> TimeBase;
multimap<int, ATBCustomer> Customer; multimap<int, ATBCustomer> Customer;
TariffProductType TariffProduct;
TariffInterpolationType TariffInterpolations;
TariffPrepaidType TariffPrepaidOptions;
TariffCarryOverType TariffCarryOverOptions;
TariffServiceType TariffServices;
TariffOutOfServiceType TariffOutOfServices;
ATBTariffPrepaidType TariffPrepaids;
ATBTariffCarryOverType TariffCarryOvers;
/// <summary> /// <summary>
/// Parse JSON string /// Parse JSON string
@ -61,16 +91,41 @@ public:
/// <returns>Returns operation status bool (OK | FAIL) </returns> /// <returns>Returns operation status bool (OK | FAIL) </returns>
bool ParseJson(Configuration* cfg, const char* json); bool ParseJson(Configuration* cfg, const char* json);
ATBPaymentOption &getPaymentOptions(); ATBPaymentOption &getPaymentOptions(int paymentOptionsIndex=0);
ATBPaymentOption const &getPaymentOptions() const; ATBPaymentOption const &getPaymentOptions(int paymentOptionsIndex=0) const;
QVector<ATBPaymentOption> &getAllPaymentOptions(); QVector<ATBPaymentOption> &getAllPaymentOptions();
QVector<ATBPaymentOption> const &getAllPaymentOptions() const; QVector<ATBPaymentOption> const &getAllPaymentOptions() const;
int getPaymentOptionIndex(QDateTime const &dt) const;
int getPaymentOptionIndexIfSpecialDay(QDateTime const &dt) const;
bool isSpecialDay(QDateTime const &dt) const;
int specialDayId(QDateTime const &dt) const;
ATBSpecialDays specialDay(QDateTime const &dt) const;
bool isDayIncluded(uint64_t businessHours, QDateTime const &dt) const;
bool isDayIncludedAsSpecialDay(uint64_t businessHours, QDateTime const &dt) const;
bool isDayIncludedAsSpecialDay(uint64_t businessHours, int specialDayId) const;
std::optional<QVector<ATBPaymentRate>> getPaymentRateForAllKeys() const; std::optional<QVector<ATBPaymentRate>> getPaymentRateForAllKeys() const;
std::optional<QVector<ATBPaymentOption>> getPaymentOptionsForAllKeys() const;
std::optional<ATBPaymentOption> getPaymentOptionForId(int key) const;
std::optional<QVector<ATBPaymentRate>> getPaymentRateForKey(int key) const; std::optional<QVector<ATBPaymentRate>> getPaymentRateForKey(int key) const;
std::optional<ATBPaymentOption> getPaymentOptionForKey(PERMIT_TYPE permitType) const;
std::optional<ATBPaymentOption> getPaymentOptionForKey(int permitType) const;
std::optional<ATBPaymentOption> getPaymentOptionForKey(QString const &permitType) const;
std::optional<QVector<ATBDailyTicket>> getDailyTicketsForAllKeys() const; std::optional<QVector<ATBDailyTicket>> getDailyTicketsForAllKeys() const;
std::optional<QVector<ATBDailyTicket>> getDailyTicketsForKey(int key) const; std::optional<QVector<ATBDailyTicket>> getDailyTicketsForKey(int key) const;
std::optional<ATBInterpolation> getInterpolationType(int type) const;
std::optional<QDateTime> getInterpolationEnd(QDateTime const &start, int paymentOptionIndex) const;
std::optional<ATBPrepaid> getPrepaidType(int type) const;
std::optional<QVector<ATBTariffProduct>> getTariffProductForAllKeys() const;
std::optional<QVector<ATBTariffProduct>> getTariffProductForProductId(int id) const;
std::optional<QVector<ATBTariffProduct>> getTariffProductForProductId(PermitType permitType) const;
std::optional<QVector<ATBTariffProduct>> getTariffProductForProductTypeName(QString const &permitTypeName) const;
std::optional<ATBCustomer> getCustomerForType(ATBCustomer::CustomerType customerType); std::optional<ATBCustomer> getCustomerForType(ATBCustomer::CustomerType customerType);
std::optional<ATBWeekDaysWorktime> getWeekDayWorkTime(QTime const &time, Qt::DayOfWeek dayOfWeek); std::optional<ATBWeekDaysWorktime> getWeekDayWorkTime(QTime const &time, Qt::DayOfWeek dayOfWeek);
std::optional<QVector<ATBWeekDaysWorktime>> getAllWeekDayWorkTimes();
std::optional<QDateTime> prepaidStart(QDateTime const &start, int prepaid_option_id);
int getPaymentOptionIndex(PERMIT_TYPE permitType);
int getPaymentOptionIndex(PERMIT_TYPE permitType) const;
private: private:
/// <summary> /// <summary>
@ -80,5 +135,17 @@ private:
/// <returns></returns> /// <returns></returns>
MemberType IdentifyJsonMember(const char* member_name); MemberType IdentifyJsonMember(const char* member_name);
QVector<ATBPaymentOption> currentPaymentOptions; QVector<ATBPaymentOption> currentPaymentOptions;
}; };
bool previousDayHoliday(Configuration const &cfg, QDateTime const &t);
bool isHoliday(Configuration const &cfg, QDateTime const &t);
int getPaymentOptionIndex(Configuration const &cfg, QDateTime const& dt = QDateTime::currentDateTime());
ATBWeekDay parseWeekDay(Configuration &cfg,
rapidjson::GenericMemberIterator<false,
rapidjson::UTF8<char>,
rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator>> k,
QString const &innerObjName,
Qt::DayOfWeek weekDay,
QString const &weekDayName);

@ -1,11 +1,40 @@
#include <string> #include <string>
#include <QDebug>
class ATBDuration class ATBDuration
{ {
public: public:
explicit ATBDuration()
: pun_id(0)
, pun_label("")
, pun_duration(0)
, pun_duration_saved(0)
, pun_duration_min(0)
, pun_duration_max(0)
, pun_interpolation_id(-1) {
}
friend QDebug operator<<(QDebug debug, ATBDuration const &td) {
QDebugStateSaver saver(debug);
debug.nospace()
<< " pun_id: " << td.pun_id << "\n"
<< " pun_label: " << QString::fromStdString(td.pun_label) << "\n"
<< " pun_duration: " << td.pun_duration << "\n"
<< " pun_duration_saved: " << td.pun_duration_saved << "\n"
<< " pun_duration_min: " << td.pun_duration_min << "\n"
<< " pun_duration_max: " << td.pun_duration_max << "\n"
<< "pun_interpolation_id: " << td.pun_interpolation_id << "\n";
return debug;
}
int pun_id; int pun_id;
std::string pun_label; std::string pun_label;
int pun_duration; int pun_duration;
int pun_duration_saved;
int pun_duration_min; int pun_duration_min;
int pun_duration_max; int pun_duration_max;
int pun_interpolation_id;
}; };

@ -18,7 +18,11 @@ enum MemberType
CustomerType = 0x0B, CustomerType = 0x0B,
TimeBaseType = 0x0C, TimeBaseType = 0x0C,
TimeRangeType = 0x0D, TimeRangeType = 0x0D,
TimeStepConfigType = 0x0E TimeStepConfigType = 0x0E,
ProductType = 0x0F,
InterpolationType = 0x10,
PrepaidType = 0x11,
CarryOverType = 0x12
}; };
#endif // MEMBER_TYPE_H_INCLUDED #endif // MEMBER_TYPE_H_INCLUDED

@ -6,7 +6,8 @@ enum PaymentMethod {
Progressive = 0x01, Progressive = 0x01,
Degressive = 0x02, Degressive = 0x02,
Linear = 0x03, Linear = 0x03,
Steps = 0x04 Steps = 0x04,
Unified = 0x05
}; };
#endif // PAYMENT_METHOD_H_INCLUDED #endif // PAYMENT_METHOD_H_INCLUDED

@ -1,5 +1,11 @@
#pragma once #ifndef PAYMENT_OPT_H_INCLUDED
#define PAYMENT_OPT_H_INCLUDED
#include <string> #include <string>
#include <cinttypes>
#include <QDateTime>
class ATBPaymentOption class ATBPaymentOption
{ {
@ -9,6 +15,8 @@ public:
void reset() { void reset() {
pop_id = 0; pop_id = 0;
pop_label = ""; pop_label = "";
pop_product_id = -1;
pop_product_name = "";
pop_payment_method_id = 0; pop_payment_method_id = 0;
pop_day_end_time = ""; pop_day_end_time = "";
pop_day_night_end_time = ""; pop_day_night_end_time = "";
@ -17,16 +25,36 @@ public:
pop_max_time = 0; pop_max_time = 0;
pop_min_price = 0; pop_min_price = 0;
pop_max_price = 0; pop_max_price = 0;
pop_max_price_save = 0;
pop_carry_over = -1; pop_carry_over = -1;
pop_carry_over_option_id = -1;
pop_prepaid_option_id = -1;
pop_truncate_last_interpolation_step = false;
pop_accumulate_prices = false;
pop_accumulate_durations = false;
pop_carry_over_target = false;
pop_carry_over_time_range_id = -1; pop_carry_over_time_range_id = -1;
pop_carry_over_start_time_range = -1;
pop_carry_over_end_time_range = -1;
pop_daily_card_price = -1; pop_daily_card_price = -1;
pop_business_hours = -1; pop_business_hours = -1;
pop_time_step_config = -1; pop_time_step_config = -1;
pop_use_only_upto_datetime = ""; // deprecated
pop_use_only_for_duration = 0; // deprecated
pop_plus_steps = 1; // +: jump <x=1> steps forward
pop_plus_steps_saved = 1;
pop_minus_steps = 1; // -: jump <x=1> steps backward
pop_allow_overpay = false;
pop_apply_carry_over_to_ticket_endtime = false;
} }
int pop_id; int pop_id;
std::string pop_label; std::string pop_label;
int pop_product_id;
QString pop_product_name;
int pop_payment_method_id; int pop_payment_method_id;
QString pop_use_only_upto_datetime;
int pop_use_only_for_duration;
std::string pop_day_end_time; std::string pop_day_end_time;
std::string pop_day_night_end_time; std::string pop_day_night_end_time;
double pop_price_night; double pop_price_night;
@ -34,9 +62,33 @@ public:
double pop_max_time; double pop_max_time;
double pop_min_price; double pop_min_price;
double pop_max_price; double pop_max_price;
double pop_max_price_save;
int pop_carry_over; int pop_carry_over;
int pop_carry_over_option_id;
bool pop_truncate_last_interpolation_step;
int pop_prepaid_option_id;
bool pop_carry_over_target;
int pop_carry_over_time_range_id; int pop_carry_over_time_range_id;
int pop_carry_over_start_time_range;
int pop_carry_over_end_time_range;
int pop_daily_card_price; int pop_daily_card_price;
int pop_business_hours; uint64_t pop_business_hours;
int pop_time_step_config; int pop_time_step_config;
bool pop_accumulate_prices;
bool pop_accumulate_durations;
int pop_plus_steps;
int pop_plus_steps_saved;
int pop_minus_steps;
bool pop_allow_overpay;
bool pop_apply_carry_over_to_ticket_endtime;
struct ATBMaxDateTime {
int direction;
uint8_t week;
uint8_t day;
QTime time;
} pop_min_date_time,
pop_max_date_time;
}; };
#endif // PAYMENT_OPT_H_INCLUDED

@ -4,10 +4,12 @@
class ATBSpecialDays class ATBSpecialDays
{ {
public: public:
explicit ATBSpecialDays() = default;
int ped_id; int ped_id;
std::string ped_label; std::string ped_label;
std::string ped_date_start; std::string ped_date_start;
std::string ped_date_end; std::string ped_date_end;
int ped_period_special_day_id; int ped_period_special_day_id;
int ped_payment_option_id;
int ped_year; int ped_year;
}; };

@ -8,5 +8,9 @@ public:
int pedwt_period_exc_day_id; int pedwt_period_exc_day_id;
std::string pedwt_time_from; std::string pedwt_time_from;
std::string pedwt_time_to; std::string pedwt_time_to;
double pedwt_price; double pedwt_price;
int pedwt_paid; // 00: not paid (i.e. free)
// 01: not paid in winter term, piad in summer term
// 10: paid in winter term, not paid in summer term
// 11: paid in winter and in summer term
}; };

@ -4,19 +4,89 @@
/// <summary> /// <summary>
/// Business hours (byte represents payment option id) /// Business hours (byte represents payment option id)
/// </summary> /// </summary>
enum BusinessHours ///
#include <Qt>
#define _NO_RESTRICTION_24_7_ (uint64_t)(0ULL)
#define _MON_ (uint64_t)(1ULL << 8)
#define _TUE_ (uint64_t)(1ULL << 9)
#define _WED_ (uint64_t)(1ULL << 10)
#define _THU_ (uint64_t)(1ULL << 11)
#define _FRI_ (uint64_t)(1ULL << 12)
#define _SAT_ (uint64_t)(1ULL << 13)
#define _SUN_ (uint64_t)(1ULL << 14)
#define _WEEK_DAYS_ ((_MON_|_TUE_|_WED_|_THU_|_FRI_))
#define _WORKING_DAYS_ ((_MON_|_TUE_|_WED_|_THU_|_FRI_|_SAT_))
#define _ALL_DAYS_ ((_MON_|_TUE_|_WED_|_THU_|_FRI_|_SAT_|_SUN_))
#define _OFFICIAL_HOLIDAY_ (uint64_t)(1ULL << 15)
#define _ONLY_WEEKEND_ ((_SAT_|_SUN_))
#define _ONLY_OPEN_FOR_BUSINESS_DAYS_ (uint64_t)(1ULL << 16) /* verkaufsoffen */
#define _WITH_RESTRICTED_HOURS_ (uint64_t)(1ULL << 17)
#define _ALL_DAYS_WITH_RESTRICTED_HOURS_ ((_WITH_RESTRICTED_HOURS_|_ALL_DAYS_))
#define _WEEKEND_WITH_RESTRICTED_HOURS_ ((_WITH_RESTRICTED_HOURS_|_FRI_|_SAT_|_SUN_))
#define _WORKING_DAYS_WITH_RESTRICTED_HOURS_ ((_WITH_RESTRICTED_HOURS_|_WORKING_DAYS_))
#define _FRI_WITH_RESTRICTED_HOURS_ ((_WITH_RESTRICTED_HOURS_|_FRI_))
#define _SAT_WITH_RESTRICTED_HOURS_ ((_WITH_RESTRICTED_HOURS_|_SAT_))
#define _SUN_WITH_RESTRICTED_HOURS_ ((_WITH_RESTRICTED_HOURS_|_SUN_))
#define _NOT_DEFINED_ (uint64_t)(~0ULL)
enum BusinessHours : std::uint64_t
{ {
NoRestriction_24_7 = 0, NoRestriction_24_7 = 0,
OnlyWorkingDays = 1, // [Monday-Friday] OnlyWorkingDays = 1, // [Monday-Friday]
OnlyWeekDays = 2, // [Monday-Saturday] OnlyWeekDays = 2, // [Monday-Saturday]
OnlyWeekEnd = 4, // [Saturday+Sunday] OnlyWeekEnd = 4, // [Saturday+Sunday]
OnlyOfficialHolidays = 8, OnlyOfficialHolidays = 8,
OnlySundaysAndHolidays = 12, // [Sun+Holiday]
OnlySpecialDays = 16, OnlySpecialDays = 16,
OnlySchoolHolidays = 32, OnlySchoolHolidays = 32,
SpecialAndSchoolHolidays = 48, SpecialAndSchoolHolidays = 48,
OnlyOpenForBusinessDays = 64, // verkaufsoffen OnlyOpenForBusinessDays = 64, // verkaufsoffen
AllDaysWithRestrictedHours = 128, // every day, restricted to some time range AllDaysWithRestrictedHours = 128, // every day, restricted to some time range
NoBusinessHoursDefined = 255 NoBusinessHoursDefined = 255,
// new 12.04.2024
NO_RESTRICTION_24_7 = _NO_RESTRICTION_24_7_,
MON = _MON_,
TUE = _TUE_,
WED = _WED_,
THU = _THU_,
FRI = _FRI_,
SAT = _SAT_,
SUN = _SUN_,
WEEK_DAYS = _WEEK_DAYS_,
WORKING_DAYS = _WORKING_DAYS_,
ALL_DAYS = _ALL_DAYS_,
OFFICIAL_HOLIDAY = _OFFICIAL_HOLIDAY_,
ONLY_WEEKEND = _ONLY_WEEKEND_,
ONLY_OPEN_FOR_BUSINESS_DAYS = _ONLY_OPEN_FOR_BUSINESS_DAYS_,
ALL_DAYS_WITH_RESTRICTED_HOURS = _ALL_DAYS_WITH_RESTRICTED_HOURS_,
WEEKEND_WITH_RESTRICTED_HOURS = _WEEKEND_WITH_RESTRICTED_HOURS_,
WORKING_DAYS_WITH_RESTRICTED_HOURS = _WORKING_DAYS_WITH_RESTRICTED_HOURS_,
FRI_WITH_RESTRICTED_HOURS = _FRI_WITH_RESTRICTED_HOURS_,
SAT_WITH_RESTRICTED_HOURS = _SAT_WITH_RESTRICTED_HOURS_,
SUN_WITH_RESTRICTED_HOURS = _SUN_WITH_RESTRICTED_HOURS_,
NOT_DEFINED = _NOT_DEFINED_
};
#if 0
static bool business(uint64_t businessHours, QDateTime &const dt) {
switch (dayOfWeek) {
case Qt::Monday:
(businessHours & _MON_) == _MON_;
case Qt::Tuesday:
case Qt::Wednesday:
case Qt::Thursday:
case Qt::Saturday:
case Qt::Sunday:
}
}
#endif
struct BusinessHours_struct {
BusinessHours bh;
}; };
#endif // TARIFF_BUSINESS_HOURS_H_INCLUDED #endif // TARIFF_BUSINESS_HOURS_H_INCLUDED

@ -0,0 +1,194 @@
#ifndef TARIFF_CARRYOVER_H_INCLUDED
#define TARIFF_CARRYOVER_H_INCLUDED
#include <QTime>
#include "time_range.h"
enum class ApplyCarryOver {
NEVER = 0,
MATCH_PREV_DAY = 1,
MATCH_NEXT_DAY = 2,
ALWAYS = 3
};
struct ATBTariffCarryOver {
int m_id;
QString m_weekDay;
TimeRange m_range;
QDate m_date;
ApplyCarryOver m_carryOverIf;
explicit ATBTariffCarryOver()
: m_id(-1)
, m_carryOverIf(ApplyCarryOver::NEVER) {
}
void setCarryOverIf(QString const &coif) {
if (coif == "never") {
m_carryOverIf = ApplyCarryOver::NEVER;
} else
if (coif == "match_prev_day") {
m_carryOverIf = ApplyCarryOver::MATCH_PREV_DAY;
} else
if (coif == "match_next_day") {
m_carryOverIf = ApplyCarryOver::MATCH_NEXT_DAY;
} else
if (coif == "always") {
m_carryOverIf = ApplyCarryOver::ALWAYS;
} else {
qCritical() << __func__ << ":" << __LINE__ << "ERROR unknown carry over application" << coif;
}
}
ApplyCarryOver carryOverIf() const {
return m_carryOverIf;
}
QString carryOverIfStr() const {
if (m_carryOverIf == ApplyCarryOver::NEVER) {
return "never";
}
if (m_carryOverIf == ApplyCarryOver::ALWAYS) {
return "always";
}
if (m_carryOverIf == ApplyCarryOver::MATCH_PREV_DAY) {
return "match prev day";
}
if (m_carryOverIf == ApplyCarryOver::MATCH_NEXT_DAY) {
return "match next day";
}
return QString("ERROR unknown carry over application: %1").arg(static_cast<int>(m_carryOverIf));
}
int computeMinutesUntilCarryOverEnd(QDateTime const &dt) {
int minutes = 0;
QString end = m_range.m_end.toString(Qt::ISODate);
if (end == "24:00:00") {
// note: this did not work
// QDateTime t(dt.addDays(1));
// t.setTime(QTime(0,0,0));
// dt: 2024-10-27T00:00:00 EEST, but t: 2024-10-28T00:00:00 EET (!)
// so the difference is 1500 instead of 1440
// reason: change from summer to winter time
// compute minutes directly
if (dt.time().isValid()) {
minutes = 1440 - (dt.time().hour() * 60 + dt.time().minute());
}
} else {
QTime t(QTime::fromString(end, Qt::ISODate));
if (t.isValid() && dt.time().isValid()) {
minutes = (t.hour() * 60 + t.minute()) - (dt.time().hour() * 60 + dt.time().minute());
}
}
if (minutes < 0 || minutes > m_range.m_duration) {
minutes = 0;
}
// qCritical() << __func__ << ":" << __LINE__ << "minutes" << minutes;
return minutes;
}
friend QDebug operator<<(QDebug debug, ATBTariffCarryOver const &co) {
QDebugStateSaver saver(debug);
debug.nospace()
<< "\nTariffCarryOver:\n"
<< " week day: " << co.m_weekDay << "\n"
<< " date: " << co.m_date.toString(Qt::ISODate) << "\n"
<< " id: " << co.m_id << "\n"
<< " start: " << co.m_range.m_start << "\n"
<< " end: " << co.m_range.m_end << "\n"
<< " duration: " << co.m_range.m_duration << "\n"
<< " carry over if: " << co.carryOverIfStr() << endl;
return debug;
}
};
struct ATBCarryOver {
struct week {
int day;
bool seemless;
bool never;
QTime static_start;
QTime static_end;
int duration;
} carryover[8];
int id;
explicit ATBCarryOver()
: id(-1) {
for (int i = 0 ; i < 8; ++i) {
carryover[i].day = -1;
carryover[i].seemless = false;
carryover[i].never = false;
carryover[i].static_start = QTime(23, 59, 59);
carryover[i].static_end = QTime(0, 0, 0);
carryover[i].duration = -1;
}
}
friend QDebug operator<<(QDebug debug, ATBCarryOver const &co) {
QDebugStateSaver saver(debug);
debug.nospace()
<< " id:" << co.id << "\n"
<< " **** Monday **** \n"
<< " day: " << co.carryover[(int)Qt::Monday].day << "\n"
<< " static_start: " << co.carryover[(int)Qt::Monday].static_start.toString(Qt::ISODate) << "\n"
<< " static_end: " << co.carryover[(int)Qt::Monday].static_end.toString(Qt::ISODate) << "\n"
<< " duration: " << co.carryover[(int)Qt::Monday].duration << "\n"
<< " anytime: " << co.carryover[(int)Qt::Monday].seemless << "\n"
<< " never: " << co.carryover[(int)Qt::Monday].never << "\n"
<< " **** Tuesday **** \n"
<< " day: " << co.carryover[(int)Qt::Tuesday].day << "\n"
<< " static_start: " << co.carryover[(int)Qt::Tuesday].static_start.toString(Qt::ISODate) << "\n"
<< " static_end: " << co.carryover[(int)Qt::Tuesday].static_end.toString(Qt::ISODate) << "\n"
<< " duration: " << co.carryover[(int)Qt::Tuesday].duration << "\n"
<< " anytime: " << co.carryover[(int)Qt::Tuesday].seemless << "\n"
<< " never: " << co.carryover[(int)Qt::Tuesday].never << "\n"
<< " **** Wednesday **** \n"
<< " day: " << co.carryover[(int)Qt::Wednesday].day << "\n"
<< " static_start: " << co.carryover[(int)Qt::Wednesday].static_start.toString(Qt::ISODate) << "\n"
<< " static_end: " << co.carryover[(int)Qt::Wednesday].static_end.toString(Qt::ISODate) << "\n"
<< " duration: " << co.carryover[(int)Qt::Wednesday].duration << "\n"
<< " anytime: " << co.carryover[(int)Qt::Wednesday].seemless << "\n"
<< " never: " << co.carryover[(int)Qt::Wednesday].never << "\n"
<< " **** Thursday **** \n"
<< " day: " << co.carryover[(int)Qt::Thursday].day << "\n"
<< " static_start: " << co.carryover[(int)Qt::Thursday].static_start.toString(Qt::ISODate) << "\n"
<< " static_end: " << co.carryover[(int)Qt::Thursday].static_end.toString(Qt::ISODate) << "\n"
<< " duration: " << co.carryover[(int)Qt::Thursday].duration << "\n"
<< " anytime: " << co.carryover[(int)Qt::Thursday].seemless << "\n"
<< " never: " << co.carryover[(int)Qt::Thursday].never << "\n"
<< " **** Friday **** \n"
<< " day: " << co.carryover[(int)Qt::Friday].day << "\n"
<< " static_start: " << co.carryover[(int)Qt::Friday].static_start.toString(Qt::ISODate) << "\n"
<< " static_end: " << co.carryover[(int)Qt::Friday].static_end.toString(Qt::ISODate) << "\n"
<< " anytime: " << co.carryover[(int)Qt::Friday].seemless << "\n"
<< " never: " << co.carryover[(int)Qt::Friday].never << "\n"
<< " **** Saturday **** \n"
<< " day: " << co.carryover[(int)Qt::Saturday].day << "\n"
<< " static_start: " << co.carryover[(int)Qt::Saturday].static_start.toString(Qt::ISODate) << "\n"
<< " static_end: " << co.carryover[(int)Qt::Saturday].static_end.toString(Qt::ISODate) << "\n"
<< " duration: " << co.carryover[(int)Qt::Saturday].duration << "\n"
<< " anytime: " << co.carryover[(int)Qt::Saturday].seemless << "\n"
<< " never: " << co.carryover[(int)Qt::Saturday].never << "\n"
<< " **** Sunday **** \n"
<< " day: " << co.carryover[(int)Qt::Sunday].day << "\n"
<< " static_start: " << co.carryover[(int)Qt::Sunday].static_start.toString(Qt::ISODate) << "\n"
<< " static_end: " << co.carryover[(int)Qt::Sunday].static_end.toString(Qt::ISODate) << "\n"
<< " duration: " << co.carryover[(int)Qt::Sunday].duration << "\n"
<< " anytime: " << co.carryover[(int)Qt::Sunday].seemless << "\n"
<< " never: " << co.carryover[(int)Qt::Sunday].never << "\n";
return debug;
}
};
#endif // TARIFF_CARRYOVER_H_INCLUDED

@ -0,0 +1,69 @@
#ifndef ATB_TARIFF_CARRYOVER_SETTINGS_H_INCLUDED
#define ATB_TARIFF_CARRYOVER_SETTINGS_H_INCLUDED
#include <QDebug>
#include <QDateTime>
#include <functional>
struct ATBTariffCarryOverSettings {
// parking time limit not violated: return false, otherwise: return true.
using ParkingTimeLimitChecker = std::function<bool(ATBTariffCarryOverSettings const&,
QDateTime const &startTime,
QDateTime const &endTime,
int paymentOptionIndex)>;
int m_duration;
QTime m_start;
QTime m_end;
ParkingTimeLimitChecker m_parkingTimeLimitChecker;
QTime m_parking_time_limit;
QTime m_about_to_exceed_parking_time_limit;
explicit ATBTariffCarryOverSettings()
: m_duration(0)
, m_start(QTime())
, m_end(QTime())
, m_parkingTimeLimitChecker([](ATBTariffCarryOverSettings const&,
QDateTime const&, QDateTime const&, int) { return false; })
, m_parking_time_limit(QTime())
, m_about_to_exceed_parking_time_limit(QTime()) {}
explicit ATBTariffCarryOverSettings(int duration, QTime const &start,
QTime const &end,
QTime const &parking_time_limit,
QTime const &about_to_exceed_parking_time_limit,
ParkingTimeLimitChecker parkingTimeLimitChecker)
: m_duration(duration)
, m_start(start)
, m_end(end)
, m_parkingTimeLimitChecker(std::move(parkingTimeLimitChecker))
, m_parking_time_limit(parking_time_limit)
, m_about_to_exceed_parking_time_limit(about_to_exceed_parking_time_limit) {
}
bool parkingTimeLimitExceeded(QDateTime const &startTime,
QDateTime const &endTime,
int paymentOptionIndex) const {
return m_parkingTimeLimitChecker(*this, startTime, endTime, paymentOptionIndex);
}
QTime const &parkingTimeLimit() const { return m_parking_time_limit; }
QTime &parkingTimeLimit() { return m_parking_time_limit; }
friend QDebug operator<<(QDebug debug, ATBTariffCarryOverSettings const &co) {
QDebugStateSaver saver(debug);
debug.nospace()
<< " duration: " << co.m_duration << "\n"
<< " start: " << co.m_start.toString(Qt::ISODate) << "\n"
<< " end: " << co.m_end.toString(Qt::ISODate) << "\n"
<< " parking_time_limit: " << co.m_parking_time_limit.toString(Qt::ISODate) << endl;
return debug;
}
};
#endif // ATB_TARIFF_CARRYOVER_SETTINGS_H_INCLUDED

@ -1,4 +1,3 @@
#pragma once
#include <variant> #include <variant>
#include <cstddef> #include <cstddef>
#include <stdio.h> #include <stdio.h>

@ -0,0 +1,20 @@
#ifndef TARIFF_GLOBAL_DEFINES_H_INCLUDED
#define TARIFF_GLOBAL_DEFINES_H_INCLUDED
#define DBG_HEADER "(" << __func__ << ":" << __LINE__ << ")"
#define DBG_EMERGENCY (0) // System is unusable
#define DBG_ALERT (1) // Action must be taken immediately
#define DBG_CRITICAL (2) // Critical conditions
#define DBG_ERROR (3) // Error conditions
#define DBG_WARNING (4) // Warning conditions
#define DBG_NOTICE (5) // Normal but significant conditions
// Conditions that are not error conditions, but that may require special handling
#define DBG_INFORMATION (6) // Informational messages
// Confirmation that the program is working as expected
#define DBG_DEBUG (7) // Debug-level messages
// Messages that contain information normally of use only when debugging a program
extern int DBG_LEVEL;
#endif // TARIFF_GLOBAL_DEFINES_H_INCLUDED

@ -0,0 +1,95 @@
#ifndef TARIFF_INTERPOLATION_H_INCLUDED
#define TARIFF_INTERPOLATION_H_INCLUDED
#include <QTime>
#include <QString>
struct ATBInterpolation {
enum Type {
NO_INTERPOLATION = 1,
STATIC_WALLCLOCK_TIME_VALUES = 2,
STATIC_TIMEPOINT_AND_DURATION = 3,
DYNAMIC_TIMEPOINT_AND_STATIC_DURATION = 4,
DYNAMIC_ABSTRACT_TIMEPOINT_AND_STATIC_DURATION = 5,
DYNAMIC_ABSTRACT_TIMEPOINT_AND_STATIC_PRICE = 6,
DYNAMIC_ABSTRACT_TIMEPOINT_AND_STATIC_END_TIME = 7
};
static QString name(int i) {
switch(i) {
case (int)(NO_INTERPOLATION):
return QString("%1: NO_INTERPOLATION").arg(i);
case (int)(STATIC_WALLCLOCK_TIME_VALUES):
return QString("%1: STATIC_WALLCLOCK_TIME_VALUES").arg(i);
case (int)(STATIC_TIMEPOINT_AND_DURATION):
return QString("%1: STATIC_TIMEPOINT_AND_DURATION").arg(i);
case (int)(DYNAMIC_TIMEPOINT_AND_STATIC_DURATION):
return QString("%1: DYNAMIC_TIMEPOINT_AND_STATIC_DURATION").arg(i);
case (int)(DYNAMIC_ABSTRACT_TIMEPOINT_AND_STATIC_DURATION):
return QString("%1: DYNAMIC_ABSTRACT_TIMEPOINT_AND_STATIC_DURATION").arg(i);
case (int)(DYNAMIC_ABSTRACT_TIMEPOINT_AND_STATIC_PRICE):
return QString("%1: DYNAMIC_ABSTRACT_TIMEPOINT_AND_STATIC_PRICE").arg(i);
case (int)(DYNAMIC_ABSTRACT_TIMEPOINT_AND_STATIC_END_TIME):
return QString("%1: DYNAMIC_ABSTRACT_TIMEPOINT_AND_STATIC_END_TIME").arg(i);
default:;
}
return "ERROR";
}
explicit ATBInterpolation()
: id(0)
, static_start(QTime())
, static_end(QTime())
, static_start_str(QString())
, static_end_str(QString())
, static_duration(0)
, dynamic_start(QTime())
, dynamic_end(QTime())
, dynamic_start_str(QString())
, dynamic_end_str(QString())
, dynamic_duration(0)
, dynamic_until_price(0)
, seemless(false)
, never(false) {
}
int id;
QTime static_start;
QTime static_end;
QString static_start_str;
QString static_end_str;
int static_duration;
QTime dynamic_start;
QTime dynamic_end;
QString dynamic_start_str;
QString dynamic_end_str;
int dynamic_duration;
int dynamic_until_price;
bool seemless;
bool never;
friend QDebug operator<<(QDebug debug, ATBInterpolation const &i) {
QDebugStateSaver saver(debug);
debug.nospace()
<< " id: " << name(i.id) << "\n"
<< " static_start: " << i.static_start.toString(Qt::ISODate) << "\n"
<< " static_end: " << i.static_end.toString(Qt::ISODate) << "\n"
<< " static_start_str: " << i.static_start_str << "\n"
<< " static_end_str: " << i.static_end_str << "\n"
<< " static_duration: " << i.static_duration << "\n"
<< " dynamic_start: " << i.dynamic_start.toString(Qt::ISODate) << "\n"
<< " dynamic_end: " << i.dynamic_end.toString(Qt::ISODate) << "\n"
<< " dynamic_start_str: " << i.dynamic_start_str << "\n"
<< " dynamic_end_str: " << i.dynamic_end_str << "\n"
<< " dynamic_duration: " << i.dynamic_duration << "\n"
<< "dynamic_until_price: " << i.dynamic_until_price << "\n"
<< " seemless: " << i.seemless << "\n"
<< " never: " << i.never << "\n";
return debug;
}
};
#endif // TARIFF_INTERPOLATION_H_INCLUDED

@ -14,6 +14,8 @@
void setDebugLevel(int level); void setDebugLevel(int level);
int getDebugLevel(); int getDebugLevel();
#if 0
static void print() { static void print() {
std::cerr << "\n"; std::cerr << "\n";
if (getDebugLevel() == DBG_LEVEL_FATAL) { if (getDebugLevel() == DBG_LEVEL_FATAL) {
@ -75,4 +77,6 @@ static void LOG_FATAL(const Arg1& arg1, const Args&&... args) {
} }
} }
#endif
#endif // TARIFF_LOG_INCLUDED_H #endif // TARIFF_LOG_INCLUDED_H

@ -0,0 +1,79 @@
#ifndef TARIFF_OUT_OF_SERVICE_H_INCLUDED
#define TARIFF_OUT_OF_SERVICE_H_INCLUDED
#include <QDateTime>
#include <QString>
#include "time_range.h"
enum class ApplyOutOfService {
NEVER = 0,
MATCH_PREV_DAY = 1,
MATCH_NEXT_DAY = 2,
ALWAYS = 3
};
struct ATBTariffOutOfService {
int m_id;
QString m_weekDay;
QDate m_date;
TimeRange m_range;
ApplyOutOfService m_outOfServiceIf;
explicit ATBTariffOutOfService()
: m_id(-1)
, m_outOfServiceIf(ApplyOutOfService::NEVER) {
}
void setOutOfServiceIf(QString const &oosif) {
if (oosif == "never") {
m_outOfServiceIf = ApplyOutOfService::NEVER;
} else
if (oosif == "match_prev_day") {
m_outOfServiceIf = ApplyOutOfService::MATCH_PREV_DAY;
} else
if (oosif == "match_next_day") {
m_outOfServiceIf = ApplyOutOfService::MATCH_NEXT_DAY;
} else
if (oosif == "always") {
m_outOfServiceIf = ApplyOutOfService::ALWAYS;
} else {
qCritical() << "ERROR unknown servcie application" << oosif;
}
}
ApplyOutOfService outOfServiceIf() const {
return m_outOfServiceIf;
}
QString outOfServiceIfStr() const {
if (m_outOfServiceIf == ApplyOutOfService::NEVER) {
return "never";
}
if (m_outOfServiceIf == ApplyOutOfService::ALWAYS) {
return "always";
}
if (m_outOfServiceIf == ApplyOutOfService::MATCH_PREV_DAY) {
return "match prev day";
}
if (m_outOfServiceIf == ApplyOutOfService::MATCH_NEXT_DAY) {
return "match next day";
}
return QString("ERROR unknown out of service application: %1").arg(static_cast<int>(m_outOfServiceIf));
}
friend QDebug operator<<(QDebug debug, ATBTariffOutOfService const &oos) {
QDebugStateSaver saver(debug);
debug.nospace()
<< "\nTariffOutOfService:\n"
<< " week day: " << oos.m_weekDay << "\n"
<< " date: " << oos.m_date.toString(Qt::ISODate) << "\n"
<< " id: " << oos.m_id << "\n"
<< " start: " << oos.m_range.m_start << "\n"
<< " end: " << oos.m_range.m_end << "\n"
<< " duration: " << oos.m_range.m_duration << endl;
return debug;
}
};
#endif // TARIFF_SERVICE_H_INCLUDED

@ -0,0 +1,263 @@
#ifndef TARIFF_PERMIT_TYPE_H_INCLUDED
#define TARIFF_PERMIT_TYPE_H_INCLUDED
#include <QString>
enum class PERMIT_TYPE : quint8 {
SHORT_TERM_PARKING=0,
DAY_TICKET=1,
SZEGED_START=2,
SZEGED_STOP=3,
DAY_TICKET_ADULT=4,
DAY_TICKET_TEEN=5,
DAY_TICKET_CHILD=6,
INVALID=7,
FOOD_STAMP=8,
TWENTY_FOUR_HOURS_TICKET=9,
SHORT_TERM_PARKING_PKW=10,
SHORT_TERM_PARKING_BUS=11,
SHORT_TERM_PARKING_CAMPER=12,
DAY_TICKET_PKW=13,
DAY_TICKET_BUS=14,
DAY_TICKET_CAMPER=15
};
struct PermitType {
PERMIT_TYPE m_permitType;
PermitType() { m_permitType = PERMIT_TYPE::INVALID; }
PermitType(int permitType) {
switch(permitType) {
case 0:
m_permitType = PERMIT_TYPE::SHORT_TERM_PARKING;
break;
case 1:
m_permitType = PERMIT_TYPE::DAY_TICKET;
break;
case 2:
m_permitType = PERMIT_TYPE::SZEGED_START;
break;
case 3:
m_permitType = PERMIT_TYPE::SZEGED_STOP;
break;
case 4:
m_permitType = PERMIT_TYPE::DAY_TICKET_ADULT;
break;
case 5:
m_permitType = PERMIT_TYPE::DAY_TICKET_TEEN;
break;
case 6:
m_permitType = PERMIT_TYPE::DAY_TICKET_CHILD;
break;
case 8:
m_permitType = PERMIT_TYPE::FOOD_STAMP;
break;
case 9:
m_permitType = PERMIT_TYPE::TWENTY_FOUR_HOURS_TICKET;
break;
case 10:
m_permitType = PERMIT_TYPE::SHORT_TERM_PARKING_PKW;
break;
case 11:
m_permitType = PERMIT_TYPE::SHORT_TERM_PARKING_BUS;
break;
case 12:
m_permitType = PERMIT_TYPE::SHORT_TERM_PARKING_CAMPER;
break;
case 13:
m_permitType = PERMIT_TYPE::DAY_TICKET_PKW;
break;
case 14:
m_permitType = PERMIT_TYPE::DAY_TICKET_BUS;
break;
case 15:
m_permitType = PERMIT_TYPE::DAY_TICKET_CAMPER;
break;
default:
m_permitType = PERMIT_TYPE::INVALID;
}
}
PermitType(PERMIT_TYPE permitType) : m_permitType(permitType) {}
void set(PERMIT_TYPE p) { m_permitType = p; }
PERMIT_TYPE get() const { return m_permitType; }
operator PERMIT_TYPE() const { return m_permitType; }
operator int () const {
switch(m_permitType) {
case PERMIT_TYPE::SHORT_TERM_PARKING:
return 0;
case PERMIT_TYPE::DAY_TICKET:
return 1;
case PERMIT_TYPE::SZEGED_START:
return 2;
case PERMIT_TYPE::SZEGED_STOP:
return 3;
case PERMIT_TYPE::DAY_TICKET_ADULT:
return 4;
case PERMIT_TYPE::DAY_TICKET_CHILD:
return 5;
case PERMIT_TYPE::DAY_TICKET_TEEN:
return 6;
case PERMIT_TYPE::FOOD_STAMP:
return 8;
case PERMIT_TYPE::TWENTY_FOUR_HOURS_TICKET:
return 9;
case PERMIT_TYPE::SHORT_TERM_PARKING_PKW:
return 10;
case PERMIT_TYPE::SHORT_TERM_PARKING_BUS:
return 11;
case PERMIT_TYPE::SHORT_TERM_PARKING_CAMPER:
return 12;
case PERMIT_TYPE::DAY_TICKET_PKW:
return 13;
case PERMIT_TYPE::DAY_TICKET_BUS:
return 14;
case PERMIT_TYPE::DAY_TICKET_CAMPER:
return 15;
default:
break;
}
return 7;
}
static PERMIT_TYPE toPermitType(QString const permitTypeStr) {
if (permitTypeStr == "DAY_TICKET") {
return PERMIT_TYPE::DAY_TICKET;
} else
if (permitTypeStr == "DAY_TICKET_ADULT") {
return PERMIT_TYPE::DAY_TICKET_ADULT;
} else
if (permitTypeStr == "DAY_TICKET_CHILD") {
return PERMIT_TYPE::DAY_TICKET_CHILD;
} else
if (permitTypeStr == "DAY_TICKET_ADULT") {
return PERMIT_TYPE::DAY_TICKET_ADULT;
} else
if (permitTypeStr == "DAY_TICKET_TEEN") {
return PERMIT_TYPE::DAY_TICKET_TEEN;
} else
if (permitTypeStr == "SHORT_TERM_PARKING") {
return PERMIT_TYPE::SHORT_TERM_PARKING;
} else
if (permitTypeStr == "SZEGED_START") {
return PERMIT_TYPE::SZEGED_START;
} else
if (permitTypeStr == "SZEGED_STOP") {
return PERMIT_TYPE::SZEGED_STOP;
} else
if (permitTypeStr == "FOOD_STAMP") {
return PERMIT_TYPE::FOOD_STAMP;
} else
if (permitTypeStr == "TWENTY_FOUR_HOURS_TICKET") {
return PERMIT_TYPE::TWENTY_FOUR_HOURS_TICKET;
} else
if (permitTypeStr == "SHORT_TERM_PARKING_PKW") {
return PERMIT_TYPE::SHORT_TERM_PARKING_PKW;
} else
if (permitTypeStr == "SHORT_TERM_PARKING_BUS") {
return PERMIT_TYPE::SHORT_TERM_PARKING_BUS;
} else
if (permitTypeStr == "SHORT_TERM_PARKING_CAMPER") {
return PERMIT_TYPE::SHORT_TERM_PARKING_CAMPER;
} else
if (permitTypeStr == "DAY_TICKET_PKW") {
return PERMIT_TYPE::DAY_TICKET_PKW;
} else
if (permitTypeStr == "DAY_TICKET_BUS") {
return PERMIT_TYPE::DAY_TICKET_BUS;
} else
if (permitTypeStr == "DAY_TICKET_CAMPER") {
return PERMIT_TYPE::DAY_TICKET_CAMPER;
}
return PERMIT_TYPE::INVALID;
}
QString toString() {
switch(m_permitType) {
case PERMIT_TYPE::DAY_TICKET:
return QString("DAY_TICKET");
case PERMIT_TYPE::DAY_TICKET_ADULT:
return QString("DAY_TICKET_ADULT");
case PERMIT_TYPE::DAY_TICKET_CHILD:
return QString("DAY_TICKET_CHILD");
case PERMIT_TYPE::DAY_TICKET_TEEN:
return QString("DAY_TICKET_TEEN");
case PERMIT_TYPE::SHORT_TERM_PARKING:
return QString("SHORT_TERM_PARKING");
case PERMIT_TYPE::SZEGED_START:
return QString("SZEGED_START");
case PERMIT_TYPE::SZEGED_STOP:
return QString("SZEGED_STOP");
case PERMIT_TYPE::FOOD_STAMP:
return QString("FOOD_STAMP");
case PERMIT_TYPE::TWENTY_FOUR_HOURS_TICKET:
return QString("TWENTY_FOUR_HOURS_TICKET");
case PERMIT_TYPE::SHORT_TERM_PARKING_PKW:
return QString("SHORT_TERM_PARKING_PKW");
case PERMIT_TYPE::SHORT_TERM_PARKING_BUS:
return QString("SHORT_TERM_PARKING_BUS");
case PERMIT_TYPE::SHORT_TERM_PARKING_CAMPER:
return QString("SHORT_TERM_PARKING_CAMPER");
case PERMIT_TYPE::DAY_TICKET_PKW:
return QString("DAY_TICKET_PKW");
case PERMIT_TYPE::DAY_TICKET_BUS:
return QString("DAY_TICKET_BUS");
case PERMIT_TYPE::DAY_TICKET_CAMPER:
return QString("DAY_TICKET_CAMPER");
default:
break;
}
return QString("INVALID");
}
QString toString() const {
switch(m_permitType) {
case PERMIT_TYPE::DAY_TICKET:
return QString("DAY_TICKET");
case PERMIT_TYPE::DAY_TICKET_ADULT:
return QString("DAY_TICKET_ADULT");
case PERMIT_TYPE::DAY_TICKET_CHILD:
return QString("DAY_TICKET_CHILD");
case PERMIT_TYPE::DAY_TICKET_TEEN:
return QString("DAY_TICKET_TEEN");
case PERMIT_TYPE::SHORT_TERM_PARKING:
return QString("SHORT_TERM_PARKING");
case PERMIT_TYPE::SZEGED_START:
return QString("SZEGED_START");
case PERMIT_TYPE::SZEGED_STOP:
return QString("SZEGED_STOP");
case PERMIT_TYPE::FOOD_STAMP:
return QString("FOOD_STAMP");
case PERMIT_TYPE::TWENTY_FOUR_HOURS_TICKET:
return QString("TWENTY_FOUR_HOURS_TICKET");
case PERMIT_TYPE::SHORT_TERM_PARKING_PKW:
return QString("SHORT_TERM_PARKING_PKW");
case PERMIT_TYPE::SHORT_TERM_PARKING_BUS:
return QString("SHORT_TERM_PARKING_BUS");
case PERMIT_TYPE::SHORT_TERM_PARKING_CAMPER:
return QString("SHORT_TERM_PARKING_CAMPER");
case PERMIT_TYPE::DAY_TICKET_PKW:
return QString("DAY_TICKET_PKW");
case PERMIT_TYPE::DAY_TICKET_BUS:
return QString("DAY_TICKET_BUS");
case PERMIT_TYPE::DAY_TICKET_CAMPER:
return QString("DAY_TICKET_CAMPER");
default:
break;
}
return QString("INVALID");
}
operator QString () {
return toString();
}
operator QString () const {
return toString();
}
};
#endif // TARIFF_PERMIT_TYPE_H_INCLUDED

@ -0,0 +1,160 @@
#ifndef TARIFF_PREPAID_H_INCLUDED
#define TARIFF_PREPAID_H_INCLUDED
#include <QDateTime>
#include <QString>
#include "time_range.h"
enum class ApplyPrepaid {
NEVER = 0,
MATCH_PREV_DAY = 1,
MATCH_NEXT_DAY = 2,
ALWAYS = 3
};
struct ATBTariffPrepaid {
int m_id;
QString m_weekDay;
QDate m_date;
TimeRange m_range;
ApplyPrepaid m_prepaidIf;
explicit ATBTariffPrepaid()
: m_id(-1)
, m_prepaidIf(ApplyPrepaid::NEVER) {
}
void setPrepaidIf(QString const &ppif) {
if (ppif == "never") {
m_prepaidIf = ApplyPrepaid::NEVER;
} else
if (ppif == "match_prev_day") {
m_prepaidIf = ApplyPrepaid::MATCH_PREV_DAY;
} else
if (ppif == "match_next_day") {
m_prepaidIf = ApplyPrepaid::MATCH_NEXT_DAY;
} else
if (ppif == "always") {
m_prepaidIf = ApplyPrepaid::ALWAYS;
} else {
qCritical() << __func__ << ":" << __LINE__ << "ERROR unknown carry over application" << ppif;
}
}
ApplyPrepaid prepaidIf() const {
return m_prepaidIf;
}
QString prepaidIfStr() const {
if (m_prepaidIf == ApplyPrepaid::NEVER) {
return "never";
}
if (m_prepaidIf == ApplyPrepaid::ALWAYS) {
return "always";
}
if (m_prepaidIf == ApplyPrepaid::MATCH_PREV_DAY) {
return "match prev day";
}
if (m_prepaidIf == ApplyPrepaid::MATCH_NEXT_DAY) {
return "match next day";
}
return QString("ERROR unknown prepaid application: %1").arg(static_cast<int>(m_prepaidIf));
}
friend QDebug operator<<(QDebug debug, ATBTariffPrepaid const &pp) {
QDebugStateSaver saver(debug);
debug.nospace()
<< "\nTariffPrepaid:\n"
<< " week day: " << pp.m_weekDay << "\n"
<< " date: " << pp.m_date.toString(Qt::ISODate) << "\n"
<< " id: " << pp.m_id << "\n"
<< " start: " << pp.m_range.m_start << "\n"
<< " end: " << pp.m_range.m_end << "\n"
<< " duration: " << pp.m_range.m_duration << "\n"
<< " prepaid if: " << pp.prepaidIfStr() << endl;
return debug;
}
};
// deprecated
struct ATBPrepaid {
int id;
bool anytime;
bool never;
QTime static_start;
QTime static_end;
struct week {
int day;
QTime static_start;
QTime static_end;
int duration;
} prepaid[8];
explicit ATBPrepaid()
: id(-1)
, anytime(false)
, never(false)
, static_start(QTime(23, 59, 59))
, static_end(QTime(0, 0, 0)) {
for (int i = 0 ; i < 8; ++i) {
prepaid[i].day = -1;
prepaid[i].static_start = QTime(23, 59, 59);
prepaid[i].static_end = QTime(0, 0, 0);
prepaid[i].duration = -1;
}
}
friend QDebug operator<<(QDebug debug, ATBPrepaid const &pp) {
QDebugStateSaver saver(debug);
debug.nospace()
<< " id: " << pp.id << "\n"
<< " static_start: " << pp.static_start.toString(Qt::ISODate) << "\n"
<< " static_end: " << pp.static_end.toString(Qt::ISODate) << "\n"
<< " anytime: " << pp.anytime << "\n"
<< " never: " << pp.never << "\n"
<< " **** Monday **** \n"
<< " day: " << pp.prepaid[(int)Qt::Monday].day << "\n"
<< " static_start: " << pp.prepaid[(int)Qt::Monday].static_start.toString(Qt::ISODate) << "\n"
<< " static_end: " << pp.prepaid[(int)Qt::Monday].static_end.toString(Qt::ISODate) << "\n"
<< " duration: " << pp.prepaid[(int)Qt::Monday].duration << "\n"
<< " **** Tuesday **** \n"
<< " day: " << pp.prepaid[(int)Qt::Tuesday].day << "\n"
<< " static_start: " << pp.prepaid[(int)Qt::Tuesday].static_start.toString(Qt::ISODate) << "\n"
<< " static_end: " << pp.prepaid[(int)Qt::Tuesday].static_end.toString(Qt::ISODate) << "\n"
<< " duration: " << pp.prepaid[(int)Qt::Tuesday].duration << "\n"
<< " **** Wednesday **** \n"
<< " day: " << pp.prepaid[(int)Qt::Wednesday].day << "\n"
<< " static_start: " << pp.prepaid[(int)Qt::Wednesday].static_start.toString(Qt::ISODate) << "\n"
<< " static_end: " << pp.prepaid[(int)Qt::Wednesday].static_end.toString(Qt::ISODate) << "\n"
<< " duration: " << pp.prepaid[(int)Qt::Wednesday].duration << "\n"
<< " **** Thursday **** \n"
<< " day: " << pp.prepaid[(int)Qt::Thursday].day << "\n"
<< " static_start: " << pp.prepaid[(int)Qt::Thursday].static_start.toString(Qt::ISODate) << "\n"
<< " static_end: " << pp.prepaid[(int)Qt::Thursday].static_end.toString(Qt::ISODate) << "\n"
<< " duration: " << pp.prepaid[(int)Qt::Thursday].duration << "\n"
<< " **** Friday **** \n"
<< " day: " << pp.prepaid[(int)Qt::Friday].day << "\n"
<< " static_start: " << pp.prepaid[(int)Qt::Friday].static_start.toString(Qt::ISODate) << "\n"
<< " static_end: " << pp.prepaid[(int)Qt::Friday].static_end.toString(Qt::ISODate) << "\n"
<< " **** Saturday **** \n"
<< " day: " << pp.prepaid[(int)Qt::Saturday].day << "\n"
<< " static_start: " << pp.prepaid[(int)Qt::Saturday].static_start.toString(Qt::ISODate) << "\n"
<< " static_end: " << pp.prepaid[(int)Qt::Saturday].static_end.toString(Qt::ISODate) << "\n"
<< " duration: " << pp.prepaid[(int)Qt::Saturday].duration << "\n"
<< " **** Sunday **** \n"
<< " day: " << pp.prepaid[(int)Qt::Sunday].day << "\n"
<< " static_start: " << pp.prepaid[(int)Qt::Sunday].static_start.toString(Qt::ISODate) << "\n"
<< " static_end: " << pp.prepaid[(int)Qt::Sunday].static_end.toString(Qt::ISODate) << "\n"
<< " duration: " << pp.prepaid[(int)Qt::Sunday].duration << "\n";
return debug;
}
};
#endif // TARIFF_PREPAID_H_INCLUDED

@ -0,0 +1,66 @@
#ifndef TARIFF_PRODUCT_H_INCLUDED
#define TARIFF_PRODUCT_H_INCLUDED
#include <QString>
#include <QDateTime>
#include <QDebug>
#include <QDebugStateSaver>
#include "tariff_permit_type.h"
struct ATBTariffProduct {
PermitType m_tariff_product_id;
uint32_t m_tariff_product_price;
QString m_tariff_product_name;
QTime m_tariff_product_start;
QTime m_tariff_product_end;
int m_tariff_product_from_in_minutes_from_start;
int m_tariff_product_to_in_minutes_from_start;
explicit ATBTariffProduct() = default;
QTime const &getTimeStart() const { return m_tariff_product_start; }
QTime const &getTimeEnd() const { return m_tariff_product_end; }
bool computeQTimeStart(QTime const &t) {
if (m_tariff_product_from_in_minutes_from_start != -1) {
m_tariff_product_start = t.addSecs(m_tariff_product_from_in_minutes_from_start * 60);
return m_tariff_product_start.isValid();
}
return false;
}
bool computeQTimeEnd(QTime const &t) {
if (m_tariff_product_to_in_minutes_from_start != -1) {
m_tariff_product_end = t.addSecs(m_tariff_product_from_in_minutes_from_start * 60);
return m_tariff_product_end.isValid();
}
return false;
}
bool computeQTimes(QTime const &t) {
if (!t.isNull() && t.isValid()) {
return computeQTimeStart(t) && computeQTimeEnd(t);
}
return false;
}
uint32_t getProductPrice() const { return m_tariff_product_price; }
friend QDebug operator<<(QDebug debug, ATBTariffProduct const &product) {
QDebugStateSaver saver(debug);
debug.nospace()
<< " m_tariff_product_id: " << QString(product.m_tariff_product_id) << "\n"
<< " m_tariff_product_name: " << product.m_tariff_product_name << "\n"
<< " m_tariff_product_price: " << product.m_tariff_product_price << "\n"
<< " m_tariff_product_start: " << product.m_tariff_product_start << "\n"
<< " m_tariff_product_end: " << product.m_tariff_product_end << "\n"
<< "m_tariff_product_from_in_minutes_from_start: " << product.m_tariff_product_from_in_minutes_from_start << "\n"
<< " m_tariff_product_to_in_minutes_from_start: " << product.m_tariff_product_to_in_minutes_from_start << "\n";
return debug;
}
};
#endif // TARIFF_PRODUCT_H_INCLUDED

@ -0,0 +1,81 @@
#ifndef TARIFF_SERVICE_H_INCLUDED
#define TARIFF_SERVICE_H_INCLUDED
#include <QDateTime>
#include <QString>
#include "time_range.h"
enum class ApplyService {
NEVER = 0,
MATCH_PREV_DAY = 1,
MATCH_NEXT_DAY = 2,
ALWAYS = 3
};
struct ATBTariffService {
int m_id;
QString m_weekDay;
QDate m_date;
TimeRange m_range;
ApplyService m_serviceIf;
explicit ATBTariffService()
: m_id(-1)
, m_serviceIf(ApplyService::NEVER) {
}
void setServiceIf(QString const &sif) {
if (sif == "never") {
m_serviceIf = ApplyService::NEVER;
} else
if (sif == "match_prev_day") {
m_serviceIf = ApplyService::MATCH_PREV_DAY;
} else
if (sif == "match_next_day") {
m_serviceIf = ApplyService::MATCH_NEXT_DAY;
} else
if (sif == "always") {
m_serviceIf = ApplyService::ALWAYS;
} else {
qCritical() << "ERROR unknown servcie application" << sif;
}
}
ApplyService serviceIf() const {
return m_serviceIf;
}
QString serviceIfStr() const {
if (m_serviceIf == ApplyService::NEVER) {
return "never";
}
if (m_serviceIf == ApplyService::ALWAYS) {
return "always";
}
if (m_serviceIf == ApplyService::MATCH_PREV_DAY) {
return "match prev day";
}
if (m_serviceIf == ApplyService::MATCH_NEXT_DAY) {
return "match next day";
}
return QString("ERROR unknown service application: %1").arg(static_cast<int>(m_serviceIf));
}
friend QDebug operator<<(QDebug debug, ATBTariffService const &ts) {
QDebugStateSaver saver(debug);
debug.nospace()
<< "\nTariffService:\n"
<< " week day: " << ts.m_weekDay << "\n"
<< " date: " << ts.m_date.toString(Qt::ISODate) << "\n"
<< " id: " << ts.m_id << "\n"
<< " start: " << ts.m_range.m_start << "\n"
<< " end: " << ts.m_range.m_end << "\n"
<< " duration: " << ts.m_range.m_duration << "\n"
<< " prepaid if: " << ts.serviceIfStr() << endl;
return debug;
}
};
#endif // TARIFF_SERVICE_H_INCLUDED

@ -0,0 +1,40 @@
#ifndef ATB_TARIFF_SETTINGS_H_INCLUDED
#define ATB_TARIFF_SETTINGS_H_INCLUDED
#include <QDebug>
struct ATBTariffSettings {
int m_max_price;
int m_min_price;
int m_max_time;
int m_min_time;
explicit ATBTariffSettings()
: m_max_price(0)
, m_min_price(0)
, m_max_time(0)
, m_min_time(0) {
}
explicit ATBTariffSettings(int max_price, int min_price, int max_time, int min_time)
: m_max_price(max_price)
, m_min_price(min_price)
, m_max_time(max_time)
, m_min_time(min_time) {
}
friend QDebug operator<<(QDebug debug, ATBTariffSettings const &ts) {
QDebugStateSaver saver(debug);
debug.nospace()
<< " max_price: " << ts.m_max_price << "\n"
<< " min_price: " << ts.m_min_price << "\n"
<< " max_time: " << ts.m_max_time << "\n"
<< " min_time: " << ts.m_min_time << endl;
return debug;
}
};
#endif // ATB_TARIFF_SETTINGS_H_INCLUDED

@ -1,12 +1,46 @@
#ifndef TIME_RANGE_H_INCLUDED #ifndef TIME_RANGE_H_INCLUDED
#define TIME_RANGE_H_INCLUDED #define TIME_RANGE_H_INCLUDED
#include "time_range_header.h" #include "atb_time.h"
#include <QString>
struct TimeRange { struct TimeRange {
public: ATBTime m_start;
bool IsActive; ATBTime m_end;
ATBTimeRange TimeRangeStructure; int m_duration;
explicit TimeRange() = default;
explicit TimeRange(QString const &start, QString const &end, int duration)
: m_start(start)
, m_end(end)
, m_duration(duration) {
}
explicit TimeRange(ATBTime const &start, ATBTime const &end, int duration)
: m_start(start)
, m_end(end)
, m_duration(duration) {
}
explicit TimeRange(TimeRange const &timeRange) {
m_start = timeRange.m_start;
m_end = timeRange.m_end;
m_duration = timeRange.m_duration;
}
TimeRange &operator=(TimeRange && timeRange) {
m_start = std::move(timeRange.m_start);
m_end = std::move(timeRange.m_end);
m_duration = timeRange.m_duration;
return *this;
}
TimeRange &operator=(TimeRange const &timeRange) {
m_start = timeRange.m_start;
m_end = timeRange.m_end;
m_duration = timeRange.m_duration;
return *this;
}
}; };
#endif // TIME_RANGE_H_INCLUDED #endif // TIME_RANGE_H_INCLUDED

@ -3,6 +3,7 @@
#include <ctime> #include <ctime>
#include <iostream> #include <iostream>
#include <cmath> #include <cmath>
#include <optional>
#include "day_of_week.h" #include "day_of_week.h"
#include "configuration.h" #include "configuration.h"
@ -15,6 +16,9 @@
using namespace std; using namespace std;
namespace Utilities { namespace Utilities {
bool isDayIncluded(uint64_t businessHours, QDateTime const &dt);
/// <summary> /// <summary>
/// Get day of week from current date (Zeller's Algorithm), starting day is Sunday /// Get day of week from current date (Zeller's Algorithm), starting day is Sunday
/// </summary> /// </summary>
@ -59,6 +63,7 @@ namespace Utilities {
/// <returns></returns> /// <returns></returns>
bool IsYearPeriodActive(Configuration* cfg, struct tm* currentDateTime); bool IsYearPeriodActive(Configuration* cfg, struct tm* currentDateTime);
bool IsYearPeriodActive(Configuration const *cfg, QDateTime const &currentDateTime); bool IsYearPeriodActive(Configuration const *cfg, QDateTime const &currentDateTime);
std::optional<ATBPeriodYear> GetYearPeriodActive(Configuration const *cfg, QDateTime const &currentDateTime);
/// <summary> /// <summary>
/// Check permissions /// Check permissions
@ -76,10 +81,12 @@ namespace Utilities {
double CalculatePricePerUnit(double pra_price, double durationUnit = -1); double CalculatePricePerUnit(double pra_price, double durationUnit = -1);
QTime SpecialDaysWorkTimeFrom(Configuration const *cfg, int specialDayId); QTime SpecialDaysWorkTimeFrom(Configuration const *cfg, int specialDayId);
QTime SpecialDaysWorkTimeFrom(Configuration::SpecialDaysWorktimeType::const_iterator const &it);
QTime SpecialDaysWorkTimeUntil(Configuration const *cfg, int specialDayId); QTime SpecialDaysWorkTimeUntil(Configuration const *cfg, int specialDayId);
QTime WeekDaysWorkTimeFrom(std::multimap<int, ATBWeekDaysWorktime>::const_iterator itr); QTime SpecialDaysWorkTimeUntil(Configuration::SpecialDaysWorktimeType::const_iterator const &it);
QTime WeekDaysWorkTimeUntil(std::multimap<int, ATBWeekDaysWorktime>::const_iterator itr); QTime WeekDaysWorkTimeFrom(std::multimap<int, ATBWeekDaysWorktime>::const_iterator const &itr);
int WeekDayId(std::multimap<int, ATBWeekDaysWorktime>::const_iterator itr); QTime WeekDaysWorkTimeUntil(std::multimap<int, ATBWeekDaysWorktime>::const_iterator const &itr);
int WeekDayId(std::multimap<int, ATBWeekDaysWorktime>::const_iterator const &itr);
// PaymentRate GetPaymentRate(Configuration const *cfg, ); // PaymentRate GetPaymentRate(Configuration const *cfg, );
bool isCarryOverSet(Configuration const *cfg, PaymentMethod paymentMethodId); bool isCarryOverSet(Configuration const *cfg, PaymentMethod paymentMethodId);
bool isCarryOverNotSet(Configuration const *cfg, PaymentMethod paymentMethodId); bool isCarryOverNotSet(Configuration const *cfg, PaymentMethod paymentMethodId);
@ -90,7 +97,10 @@ namespace Utilities {
uint32_t getMinimalParkingPrice(Configuration const *cfg, PaymentMethod methodId); uint32_t getMinimalParkingPrice(Configuration const *cfg, PaymentMethod methodId);
uint32_t getMaximalParkingPrice(Configuration const *cfg, PaymentMethod methodId); uint32_t getMaximalParkingPrice(Configuration const *cfg, PaymentMethod methodId);
uint32_t getFirstDurationStep(Configuration const *cfg, PaymentMethod methodId); uint32_t getFirstDurationStep(Configuration const *cfg, PaymentMethod methodId);
uint32_t getTimeRangeStep(Configuration const *cfg, int step, PaymentMethod methodId);
BusinessHours getBusinessHours(Configuration const *cfg, PaymentMethod methodId); BusinessHours getBusinessHours(Configuration const *cfg, PaymentMethod methodId);
uint32_t computeWeekDaysPrice(Configuration const *cfg, PaymentMethod id); uint32_t computeWeekDaysPrice(Configuration const *cfg, PaymentMethod id);
double computeWeekDaysDurationUnit(Configuration const *cfg, PaymentMethod id); double computeWeekDaysDurationUnit(Configuration const *cfg, PaymentMethod id);
QStringList dumpBusinessHours(uint64_t businessHours);
uint32_t getDailyTicketCardPrice(Configuration const *cfg, PaymentMethod methodId);
} }

@ -1,10 +1,57 @@
#pragma once #include "tariff_settings.h"
#include <string> #include "tariff_carryover_settings.h"
class ATBWeekDays #include <QString>
{ #include <Qt>
public: #include <QDate>
int pdiw_id;
std::string pdiw_label; struct ATBWeekDay {
int pdiw_index; enum WeekDayType {USUAL_WEEKDAY=0, HOLIDAY=1};
Qt::DayOfWeek m_id;
QString m_name;
QDate m_date;
WeekDayType m_type;
ATBTariffSettings m_tariffSettings;
ATBTariffCarryOverSettings m_tariffCarryOverSettings;
explicit ATBWeekDay()
: m_id(Qt::Monday)
, m_name("")
, m_date(QDate())
, m_type(USUAL_WEEKDAY)
, m_tariffSettings()
, m_tariffCarryOverSettings() {}
explicit ATBWeekDay(Qt::DayOfWeek id, QString const &name, WeekDayType type,
QDate const &date,
ATBTariffSettings const &tariffSettings,
ATBTariffCarryOverSettings const &tariffCarryOverSettings)
: m_id(id)
, m_name(name)
, m_date(date)
, m_type(type)
, m_tariffSettings(tariffSettings)
, m_tariffCarryOverSettings(tariffCarryOverSettings) {}
ATBTariffCarryOverSettings &getTariffCarryOverSettings() { return m_tariffCarryOverSettings; }
ATBTariffCarryOverSettings const &getTariffCarryOverSettings() const { return m_tariffCarryOverSettings; }
ATBTariffSettings &getTariffSettings() { return m_tariffSettings; }
ATBTariffSettings const &getTariffSettings() const { return m_tariffSettings; }
friend QDebug operator<<(QDebug debug, ATBWeekDay const &wd) {
QDebugStateSaver saver(debug);
debug.nospace()
<< " id: " << (int)wd.m_id << "\n"
<< " name: " << wd.m_name << "\n"
<< " type: " << (int)wd.m_type << "\n\n"
<< " tariff settings: " << "\n"
<< wd.m_tariffSettings << "\n"
<< "tariff carryover settings: " << "\n"
<< wd.m_tariffCarryOverSettings << endl;
return debug;
}
}; };

@ -4,8 +4,10 @@
class ATBWeekDaysWorktime class ATBWeekDaysWorktime
{ {
public: public:
int pwd_id; int pwd_id;
int pwd_period_week_day_id; int pwd_pop_id;
int pwd_next_id;
int pwd_period_week_day_id;
int pwd_period_day_in_week_id; int pwd_period_day_in_week_id;
std::string pwd_time_from; std::string pwd_time_from;
std::string pwd_time_to; std::string pwd_time_to;

File diff suppressed because it is too large Load Diff

@ -12,6 +12,10 @@ INCLUDEPATH += $$_PRO_FILE_PWD_/include/rapidjson
#Version is set in yocto recipe with "EXTRA_QMAKEVARS_PRE" #Version is set in yocto recipe with "EXTRA_QMAKEVARS_PRE"
#VERSION=1.0.0 #VERSION=1.0.0
# 04.06.2024: Fix for Szeged: read price for daily ticket directly from entry
# PaymentOptions in tariff-file if it is not given as part of a
# Json-Product-Array in tariff-file.
CONFIG(debug, debug|release) { CONFIG(debug, debug|release) {
win32 { win32 {
QMAKE_CXXFLAGS += -DCALCULATE_LIBRARY_EXPORTS QMAKE_CXXFLAGS += -DCALCULATE_LIBRARY_EXPORTS
@ -30,7 +34,9 @@ SOURCES += \
src/configuration.cpp \ src/configuration.cpp \
src/tariff_log.cpp \ src/tariff_log.cpp \
src/calculate_price.cpp \ src/calculate_price.cpp \
src/ticket.cpp src/ticket.cpp \
src/tariff_global_defines.cpp \
src/atb_time.cpp
HEADERS += \ HEADERS += \
include/mobilisis/calculator_functions.h \ include/mobilisis/calculator_functions.h \
@ -77,7 +83,17 @@ HEADERS += \
include/mobilisis/tariff_daily_ticket.h \ include/mobilisis/tariff_daily_ticket.h \
include/mobilisis/tariff_customer.h \ include/mobilisis/tariff_customer.h \
include/mobilisis/tariff_timebase.h \ include/mobilisis/tariff_timebase.h \
include/mobilisis/tariff_timestep_config.h include/mobilisis/tariff_timestep_config.h \
include/mobilisis/tariff_product.h \
include/mobilisis/tariff_permit_type.h \
include/mobilisis/tariff_global_defines.h \
include/mobilisis/tariff_interpolation.h \
include/mobilisis/tariff_prepaid.h \
include/mobilisis/tariff_carryover.h \
include/mobilisis/tariff_global_defines.h \
include/mobilisis/atb_time.h \
include/mobilisis/tariff_service.h \
include/mobilisis/tariff_out_of_service.h
OTHER_FILES += src/main.cpp \ OTHER_FILES += src/main.cpp \
../tariffs/tariff_korneuburg.json \ ../tariffs/tariff_korneuburg.json \

151
library/src/atb_time.cpp Normal file

@ -0,0 +1,151 @@
#include "atb_time.h"
#include <QDebugStateSaver>
QDateTime const ATBTime::m_end(QDateTime::fromString("1970-01-02T00:00:00", Qt::ISODate));
ATBTime::ATBTime()
: m_time(QDateTime::fromString("1970-01-01T00:00:00", Qt::ISODate)) {
}
ATBTime::ATBTime(int h, int m, int /*s*/, int /*ms*/)
: m_time(QDateTime::fromString("1970-01-01T00:00:00", Qt::ISODate)) {
if (h == 24 && m == 0) {
m_time = m_end;
} else {
QTime const t(h, m, 0, 0);
m_time.setTime(t);
}
}
ATBTime::ATBTime(QString const &t)
: m_time(QDateTime::fromString("1970-01-01T00:00:00")) {
if (t == "24:00:00") {
m_time = m_end;
} else {
QTime tmp = QTime::fromString(t, Qt::ISODate);
if (tmp.isValid()) {
m_time.setTime(tmp);
}
}
}
ATBTime::ATBTime(QTime const &t)
: m_time(QDateTime::fromString("1970-01-01T00:00:00")) {
m_time.setTime(t);
}
QTime ATBTime::addMSecs(int ms) const {
return m_time.time().addMSecs(ms);
}
QTime ATBTime::addMSecs(int ms) {
QTime t = m_time.time();
t = t.addMSecs(ms);
m_time.setTime(t);
return t;
}
QTime ATBTime::addSecs(int s) const {
return m_time.time().addSecs(s);
}
QTime ATBTime::addSecs(int s) {
QTime t = m_time.time();
t = t.addSecs(s);
m_time.setTime(t);
return t;
}
constexpr QTime ATBTime::fromMSecsSinceStartOfDay(int msecs) {
return QTime::fromMSecsSinceStartOfDay(msecs);
}
QTime ATBTime::fromString(QString const &string, Qt::DateFormat format) {
return QTime::fromString(string, format);
}
QTime ATBTime::fromString(QString const &string, QString const &format) {
return QTime::fromString(string, format);
}
bool ATBTime::isValid(int h, int m, int s, int ms) {
return QTime(h, m, s, ms).isValid();
}
int ATBTime::msecsSinceStartOfDay() const {
return m_time.time().msecsSinceStartOfDay();
}
bool ATBTime::setHMS(int h, int m, int s, int ms) {
if (isValid(h, m, s, ms)) {
QTime t(h, m, s, ms);
m_time.setTime(t);
return true;
}
return false;
}
QString ATBTime::toString(Qt::DateFormat format) const {
if (m_time == m_end) {
return "24:00:00";
}
return m_time.time().toString(format);
}
bool operator!=(const ATBTime &lhs, const ATBTime &rhs) noexcept {
return lhs.m_time.time() != rhs.m_time.time();
}
bool operator<=(const ATBTime &lhs, const ATBTime &rhs) noexcept {
if (rhs.m_time == rhs.m_end) {
return true;
}
return lhs.m_time.time() <= rhs.m_time.time();
}
bool operator>=(const ATBTime &lhs, const ATBTime &rhs) noexcept {
return lhs.m_time.time() >= rhs.m_time.time();
}
bool operator<(const ATBTime &lhs, const ATBTime &rhs) noexcept {
if (rhs.m_time == rhs.m_end) {
return true;
}
return lhs.m_time.time() < rhs.m_time.time();
}
bool operator>(const ATBTime &lhs, const ATBTime &rhs) noexcept {
return lhs.m_time.time() > rhs.m_time.time();
}
bool operator==(const ATBTime &lhs, const ATBTime &rhs) noexcept {
return lhs.m_time.time() == rhs.m_time.time();
}
QDebug &operator<<(QDebug &debug, ATBTime const &time) {
QDebugStateSaver saver(debug);
if (time.m_time == time.m_end) {
debug.nospace() << QString("24:00:00");
} else {
debug.nospace() << time.m_time.time().toString(Qt::ISODate);
}
return debug;
}
QDataStream &operator<<(QDataStream &out, ATBTime const &time) {
if (time.m_time == time.m_end) {
out << QString("24:00:00");
} else {
out << time.m_time.time();
}
return out;
}
QDataStream &operator>>(QDataStream &in, ATBTime &time) {
QTime t;
in >> t;
time.m_time.setTime(t);
return in;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,762 @@
#include "calculate_price.h"
#include "configuration.h"
#include "calculator_functions.h"
#include "payment_option.h"
#include "utilities.h"
#include <QFile>
#include <QFileInfo>
#include <QDateTime>
#include <QDebug>
#include <QList>
QString const CalcState::SUCCESS = "SUCCESS";
QString const CalcState::ERROR_PARSING_ZONE_NR = "ERROR_PARSING_ZONE_NR";
QString const CalcState::ERROR_LOADING_TARIFF = "ERROR_LOADING_TARIFF";
QString const CalcState::ERROR_PARSING_TARIFF = "ERROR_PARSING_TARIFF";
QString const CalcState::NEGATIVE_PARKING_TIME = "NEGATIVE_PARKING_TIME";
QString const CalcState::INVALID_START_DATE = "INVALID_START_DATE";
QString const CalcState::WRONG_PARAM_VALUES = "WRONG_PARAM_VALUES";
QString const CalcState::WRONG_ISO_TIME_FORMAT = "WRONG_ISO_TIME_FORMAT";
QString const CalcState::ABOVE_MAX_PARKING_TIME = "ABOVE_MAX_PARKING_TIME";
QString const CalcState::BELOW_MIN_PARKING_TIME = "BELOW_MIN_PARKING_TIME";
QString const CalcState::BELOW_MIN_PARKING_PRICE = "BELOW_MIN_PARKING_PRICE";
QString const CalcState::ABOVE_MAX_PARKING_PRICE = "ABOVE_MAX_PARKING_PRICE";
QString const CalcState::OVERPAID = "OVERPAID";
QString const CalcState::OUTSIDE_ALLOWED_PARKING_TIME = "OUTSIDE_ALLOWED_PARKING_TIME";
QList<int> CALCULATE_LIBRARY_API get_time_steps(Configuration *cfg) {
return Calculator::GetInstance().GetTimeSteps(cfg);
}
int CALCULATE_LIBRARY_API get_minimal_parkingtime(Configuration const *cfg,
PERMIT_TYPE permitType,
int paymentOptionIndex) {
int minTime = 0;
switch(permitType) {
case PERMIT_TYPE::SHORT_TERM_PARKING: { // e.g. szeged (customer_281)
QList<int> const tsteps = Calculator::GetInstance().GetTimeSteps((Configuration *)cfg, paymentOptionIndex);
Q_UNUSED(tsteps);
minTime = cfg->getPaymentOptions(paymentOptionIndex).pop_min_time;
} break;
case PERMIT_TYPE::DAY_TICKET_ADULT: {
} break;
case PERMIT_TYPE::DAY_TICKET_TEEN: {
} break;
case PERMIT_TYPE::DAY_TICKET_CHILD: {
} break;
default:
// for each new sell-procedure, recomute the timesteps. implicitly, set
// the minimal parking time.
Calculator::GetInstance().ResetTimeSteps(paymentOptionIndex);
Calculator::GetInstance().GetTimeSteps((Configuration *)cfg, paymentOptionIndex);
minTime = qRound(cfg->getPaymentOptions(paymentOptionIndex).pop_min_time);
}
return minTime;
}
int CALCULATE_LIBRARY_API get_maximal_parkingtime(Configuration const *cfg,
PERMIT_TYPE permitType,
int paymentOptionIndex) {
int maxTime = 0;
switch(permitType) {
case PERMIT_TYPE::SHORT_TERM_PARKING: { // e.g. szeged (customer_281)
maxTime = cfg->getPaymentOptions(paymentOptionIndex).pop_max_time;
} break;
case PERMIT_TYPE::DAY_TICKET_ADULT: {
} break;
case PERMIT_TYPE::DAY_TICKET_TEEN: {
} break;
case PERMIT_TYPE::DAY_TICKET_CHILD: {
} break;
default: ;
}
return maxTime;
}
int CALCULATE_LIBRARY_API get_minimal_parkingprice(Configuration *cfg,
PERMIT_TYPE permitType,
int paymentOptionIndex,
QDateTime const &start) {
int minPrice = -1;
switch(permitType) {
case PERMIT_TYPE::SHORT_TERM_PARKING: { // e.g. szeged (customer_281)
minPrice = cfg->getPaymentOptions(paymentOptionIndex).pop_min_price;
} break;
case PERMIT_TYPE::DAY_TICKET_ADULT: {
} break;
case PERMIT_TYPE::DAY_TICKET_TEEN: {
} break;
case PERMIT_TYPE::DAY_TICKET_CHILD: {
} break;
case PERMIT_TYPE::DAY_TICKET: {
minPrice = compute_product_price(cfg, permitType, start);
} break;
default: ;
}
return minPrice;
}
int CALCULATE_LIBRARY_API compute_product_price(Configuration const *cfg,
PERMIT_TYPE permitType,
QDateTime const &start,
QDateTime *productStart,
QDateTime *productEnd) {
switch(permitType) {
case PERMIT_TYPE::SHORT_TERM_PARKING: { // e.g. szeged (customer_281)
} break;
case PERMIT_TYPE::DAY_TICKET_CHILD:
// [[fallthrough]];
case PERMIT_TYPE::DAY_TICKET_TEEN:
// [[fallthrough]];
case PERMIT_TYPE::FOOD_STAMP:
// [[fallthrough]];
case PERMIT_TYPE::DAY_TICKET_ADULT: {
std::optional<QVector<ATBTariffProduct>> products = cfg->getTariffProductForProductId(permitType);
if (products) {
QVector<ATBTariffProduct> product = products.value();
if (product.size() > 0) {
ATBTariffProduct const &p = product[0];
return p.m_tariff_product_price;
#if 0
// in case we do not have prepaid-option
QTime const &currentTime = QDateTime::currentDateTime().time();
if (p.m_tariff_product_start <= currentTime && currentTime <= p.m_tariff_product_end) {
return p.m_tariff_product_price;
} else {
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "ERROR currentTime"
<< currentTime.toString(Qt::ISODate)
<< "INVALID ("
<< p.m_tariff_product_start.toString(Qt::ISODate)
<< p.m_tariff_product_end.toString(Qt::ISODate) << ")";
}
#endif
}
}
} break;
case PERMIT_TYPE::INVALID:
// [[fallthrough]];
case PERMIT_TYPE::DAY_TICKET: {
std::optional<QVector<ATBTariffProduct>> products = cfg->getTariffProductForProductId(permitType);
if (products) {
QVector<ATBTariffProduct> product = products.value();
int product_price = 0;
if (productStart && productEnd) {
*productStart = start;
*productEnd = start;
if (product.size() > 0) {
productStart->setTime(product[0].getTimeStart());
productEnd->setTime(product[0].getTimeEnd());
}
}
for (QVector<ATBTariffProduct>::size_type i=0; i<product.size(); ++i) {
ATBTariffProduct const &p = product[i];
QTime const &startTime = p.getTimeStart();
QTime const &endTime = p.getTimeEnd();
// qCritical() << __LINE__ << startTime.toString(Qt::ISODate);
// qCritical() << __LINE__ << endTime.toString(Qt::ISODate);
// qCritical() << __LINE__ << start.toString(Qt::ISODate);
if (start.time() >= startTime && start.time() < endTime) {
product_price = p.getProductPrice();
if (productStart && productEnd) {
productStart->setTime(startTime);
productEnd->setTime(endTime);
}
}
}
return product_price;
} else {
// SZEGED
int const pop_daily_card_price = cfg->getPaymentOptions().pop_daily_card_price;
qDebug() << QString("(%1:%2) no products defined in tariff-file").arg(__func__).arg(__LINE__);
qDebug() << QString("(%1:%2) pop_daily_card_price=%3").arg(__func__).arg(__LINE__).arg(pop_daily_card_price);
// static const PaymentMethod paymentMethodId = Utilities::getPaymentMethodId(cfg);
// return Utilities::getDailyTicketCardPrice(cfg, paymentMethodId);
return pop_daily_card_price;
}
} break;
case PERMIT_TYPE::TWENTY_FOUR_HOURS_TICKET: {
std::optional<QVector<ATBTariffProduct>> products = cfg->getTariffProductForProductId(permitType);
if (products) {
int product_price = 0;
QVector<ATBTariffProduct> product = products.value();
if (product.size() > 0) {
if (productStart && productEnd) {
int pop_min_time = get_minimal_parkingtime(cfg); // in minutes
int pop_max_time = get_maximal_parkingtime(cfg); // in minutes
if (pop_max_time >= pop_min_time) {
*productStart = start;
*productEnd = start.addSecs(pop_max_time*60);
product_price = product[0].getProductPrice();
}
}
}
return product_price;
}
} break;
default:
break;
}
return 0;
}
int CALCULATE_LIBRARY_API get_maximal_parkingprice(Configuration *cfg,
PERMIT_TYPE permitType,
int paymentOptionIndex) {
int maxPrice = -1;
static const PaymentMethod paymentMethodId = Utilities::getPaymentMethodId(cfg);
switch(permitType) {
case PERMIT_TYPE::SHORT_TERM_PARKING: { // e.g. szeged (customer_281)
if (paymentMethodId == PaymentMethod::Progressive || paymentMethodId == PaymentMethod::Steps) {
maxPrice = Utilities::getMaximalParkingPrice(cfg, paymentMethodId);
} else { // PaymentMethod::Linear -> e.g. szeged
int const key = cfg->getPaymentOptions(paymentOptionIndex).pop_id;
int const maxTime = cfg->getPaymentOptions(paymentOptionIndex).pop_max_time; // maxTime is given in minutes
std::optional<QVector<ATBPaymentRate>> const &pv = cfg->getPaymentRateForKey(key);
if (pv) {
QVector<ATBPaymentRate> const &paymentRate = pv.value();
if (paymentRate.size() > 0) {
int const price = paymentRate.last().pra_price; // price is given per hour
maxPrice = qRound((maxTime * price) / 60.0f);
}
}
}
} break;
case PERMIT_TYPE::DAY_TICKET_ADULT:
break;
case PERMIT_TYPE::DAY_TICKET_TEEN:
break;
case PERMIT_TYPE::DAY_TICKET_CHILD:
break;
default: ;
}
return maxPrice;
}
int CALCULATE_LIBRARY_API get_zone_nr(int zone)
{
if(zone > -1) return zone;
else
{
QFile zone("/etc/zone_nr");
if (zone.exists()) {
QFileInfo finfo(zone);
if (finfo.size() <= 4) { // decimal 000\n
if (zone.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&zone);
return in.readLine(100).toInt();
}
}
}
return -1;
}
}
CalcState CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff, char const *config_file) {
*tariff = new Configuration();
CalcState calcState;
#if __linux__
int const zone = get_zone_nr();
// DEBUG
qCritical() << "init_tariff:";
qCritical() << " ... zone = " << zone;
if (zone <= 0) {
delete *tariff;
*tariff = nullptr;
return calcState.set(CalcState::State::ERROR_PARSING_ZONE_NR);
}
QString confFile(config_file);
if (!confFile.endsWith(QChar('/'))) {
confFile += "/";
}
char buffer[32];
memset(buffer, 0x00, sizeof(buffer));
snprintf(buffer, sizeof(buffer)-1, "tariff%02d.json", zone);
confFile += buffer;
#else // windows
QString confFile(config_file);
#endif
// DEBUG
qCritical() << " ... confFile = " << confFile;
QFile fname(confFile);
if (fname.exists() &&
fname.open(QIODevice::ReadOnly | QIODevice::Text)) {
// DEBUG
qCritical() << " ... confFile is open";
QString json = fname.readAll();
if (! (*tariff)->ParseJson(*tariff, json.toStdString().c_str())) {
delete *tariff;
*tariff = nullptr;
return calcState.set(CalcState::State::ERROR_PARSING_TARIFF);
}
} else {
delete *tariff;
*tariff = nullptr;
return calcState.set(CalcState::State::ERROR_LOADING_TARIFF);
}
qCritical() << "init_tariff: Parsing tariff config (" << confFile << ")";
return calcState;
}
void CALCULATE_LIBRARY_API free_tariff(parking_tariff_t *tariff) {
if (tariff != nullptr) {
delete tariff;
}
}
//
// UpDown 1 -> up; 0 -> down
int CALCULATE_LIBRARY_API compute_next_timestep(parking_tariff_t *tariff, int currentTimeMinutes, int UpDown)
{
qCritical() << " compute_next_timestep() currentTimeMinutes: " << currentTimeMinutes;
qCritical() << " compute_next_timestep() up/down (1=up, 0=down): " << UpDown;
Configuration const *cfg = tariff;
// compute payment method id (e.g. Linear=3, Steps=4)
PaymentMethod const paymentMethodId = Utilities::getPaymentMethodId(cfg);
switch (paymentMethodId) {
case PaymentMethod::Progressive:
qCritical() << " compute_next_timestep() paymentMethodId: Progressive";
break;
case PaymentMethod::Degressive:
qCritical() << " compute_next_timestep() paymentMethodId: Degressive";
break;
case PaymentMethod::Linear:
qCritical() << " compute_next_timestep() paymentMethodId: Linear";
break;
case PaymentMethod::Steps:
qCritical() << " compute_next_timestep() paymentMethodId: Steps";
break;
case PaymentMethod::Undefined:
qCritical() << " compute_next_timestep() paymentMethodId: Undefined";
break;
}
// use tariff with structure as for instance Schnau, Koenigsee:
// without given YearPeriod, SpecialDays and SpecialDaysWorktime
if ((paymentMethodId == PaymentMethod::Steps) ||
// progressive tariff: e.g. Neuhauser, Kirchdorf (743)
(paymentMethodId == PaymentMethod::Progressive))
{
const QList<int> stepList = Calculator::GetInstance().GetTimeSteps(tariff);
qCritical() << " compute_next_timestep() timeSteps:" << stepList;
int currentStepIndex = stepList.indexOf(currentTimeMinutes);
if (currentStepIndex == -1) {
qCritical() << "compute_next_timestep() *NO STEP* for currentTimeMinutes (" << currentTimeMinutes << ")";
return currentTimeMinutes;
}
if (UpDown == 1) { // UP
if (stepList[currentStepIndex] == stepList.last()) {
qCritical() << "compute_next_timestep() *NO NEXT STEP* for currentTimeMinutes (" << currentTimeMinutes << ")";
return currentTimeMinutes;
}
else {
return stepList[currentStepIndex + 1];
}
}
if (UpDown == 0) { // DOWN
if (stepList[currentStepIndex] == stepList.first()) {
qCritical() << "compute_next_timestep() *NO PREVIOUS STEP* for currentTimeMinutes (" << currentTimeMinutes << ")";
return currentTimeMinutes;
}
else {
return stepList[currentStepIndex - 1];
}
}
} else
if (paymentMethodId == PaymentMethod::Linear) {
// currentTimeMinutes is the number of minutes actually used. This
// value is an offset from the start time and cannot be used as a
// QDateTime.
qCritical() << "compute_next_timestep() up/down (1=up, 0=down):" << UpDown;
// get minimal and maximal parking times
int const minParkingTime = Utilities::getMinimalParkingTime(cfg, paymentMethodId);
int const maxParkingTime = Utilities::getMaximalParkingTime(cfg, paymentMethodId);
qCritical() << " compute_next_timestep() maxParkingTime:" << maxParkingTime;
qCritical() << " compute_next_timestep() minParkingTime:" << minParkingTime;
// use the first (i.e. main duration step contained in the tariff json-file)
int firstDurationStep = Utilities::getFirstDurationStep(cfg, paymentMethodId);
firstDurationStep = ((UpDown == 1) ? firstDurationStep : -firstDurationStep);
qCritical() << " compute_next_timestep() firstDurationStep:" << firstDurationStep;
int const nextTimeStep = currentTimeMinutes + firstDurationStep;
if (nextTimeStep >= minParkingTime && nextTimeStep <= maxParkingTime) {
qCritical() << " compute_next_timestep() nextTimeStep:" << nextTimeStep;
return nextTimeStep;
}
}
qCritical() << "compute_next_timestep() *CAN NOT COMPUTE* for currentTimeMinutes (" << currentTimeMinutes << ")";
return currentTimeMinutes;
}
// this is currently not used
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
parking_tariff_t *tariff,
time_t start_parking_time, // in minutes
time_t end_parking_time, // netto time in minutes
struct price_t *price) {
CalcState calcState;
double minMin = tariff->PaymentOption.find(tariff->getPaymentOptions().pop_payment_method_id)->second.pop_min_time;
double maxMin = tariff->PaymentOption.find(tariff->getPaymentOptions().pop_payment_method_id)->second.pop_max_time;
if (minMin < 0 || maxMin < 0 || maxMin < minMin) {
calcState.setDesc(QString("minMin=%1, maxMin=%2").arg(minMin).arg(maxMin));
return calcState.set(CalcState::State::WRONG_PARAM_VALUES);
}
int const duration = end_parking_time - start_parking_time;
if (duration < 0) {
calcState.setDesc(QString("end=%1, start=%2")
.arg(end_parking_time, start_parking_time));
return calcState.set(CalcState::State::NEGATIVE_PARKING_TIME);
}
if (duration > maxMin) {
calcState.setDesc(QString("duration=%1, maxMin=%2").arg(duration).arg(maxMin));
return calcState.set(CalcState::State::ABOVE_MAX_PARKING_TIME);
}
if (duration < minMin) {
calcState.setDesc(QString("duration=%1, minMin=%2").arg(duration).arg(minMin));
return calcState.set(CalcState::State::BELOW_MIN_PARKING_TIME);
}
if (duration == 0) {
return calcState.set(CalcState::State::SUCCESS);
}
QDate const d(1970, 1, 1);
QTime const t(0, 0, 0);
QDateTime start(d, t, Qt::UTC);
start = start.toLocalTime().addSecs(start_parking_time * 60);
QDateTime end(start);
if (start.isValid()) {
double cost = Calculator::GetInstance().GetCostFromDuration(
tariff,
tariff->getPaymentOptions().pop_payment_method_id,
start,
end,
duration, false, true);
double minCost = tariff->PaymentOption.find(tariff->getPaymentOptions().pop_payment_method_id)->second.pop_min_price;
if (cost < minCost) {
calcState.setDesc(QString("minCost=%1, cost=%2").arg(minCost).arg(cost));
return calcState.set(CalcState::State::BELOW_MIN_PARKING_PRICE);
}
price->units = cost;
price->netto = cost;
} else {
return calcState.set(CalcState::State::INVALID_START_DATE);
}
return calcState.set(CalcState::State::SUCCESS);
}
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
parking_tariff_t *tariff,
QDateTime &start_parking_time,
int netto_parking_time,
QDateTime &end_parking_time,
struct price_t *price,
bool prepaid)
{
CalcState calcState;
int paymentOptionIndex = tariff->getPaymentOptionIndex(start_parking_time);
double minMin = tariff->getPaymentOptions(paymentOptionIndex).pop_min_time;
double maxMin = tariff->getPaymentOptions(paymentOptionIndex).pop_max_time;
// DEBUG
qCritical() << "compute_price_for_parking_ticket() " << endl
<< " paymentOptionIndex: " << paymentOptionIndex << endl
<< " start_parking_time: " << start_parking_time << endl
<< " netto_parking_time: " << netto_parking_time << endl
<< " minMin: " << minMin << endl
<< " maxMin: " << maxMin;
if (netto_parking_time < 0) {
calcState.setDesc(QString("end=%1, start=%2")
.arg(end_parking_time.toString(Qt::ISODate),
start_parking_time.toString(Qt::ISODate)));
return calcState.set(CalcState::State::NEGATIVE_PARKING_TIME);
}
if (netto_parking_time > maxMin) {
calcState.setDesc(QString("duration=%1, maxMin=%2").arg(netto_parking_time).arg(maxMin));
return calcState.set(CalcState::State::ABOVE_MAX_PARKING_TIME);
}
if (netto_parking_time < minMin) {
calcState.setDesc(QString("duration=%1, minMin=%2").arg(netto_parking_time).arg(minMin));
return calcState.set(CalcState::State::BELOW_MIN_PARKING_TIME);
}
if (netto_parking_time == 0) {
return calcState.set(CalcState::State::SUCCESS);
}
double cost = -1;
if (start_parking_time.isValid()) {
if (tariff->getPaymentOptions(paymentOptionIndex).pop_payment_method_id == PaymentMethod::Steps) {
// hier muesste man unterscheiden: uebertrag oder nicht?
calcState = Calculator::GetInstance().isParkingAllowed(tariff, start_parking_time,
netto_parking_time, paymentOptionIndex);
if (calcState.getStatus() == CalcState::State::OUTSIDE_ALLOWED_PARKING_TIME) {
// qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
// << calcState.toString();
return calcState;
}
cost = Calculator::GetInstance().GetCostFromDuration(tariff, start_parking_time, netto_parking_time, paymentOptionIndex);
end_parking_time = start_parking_time.addSecs(netto_parking_time*60);
// qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
// << "end_parking_time" << end_parking_time.toString(Qt::ISODate);
} else {
cost = Calculator::GetInstance().GetCostFromDuration(
tariff,
tariff->getPaymentOptions().pop_payment_method_id,
start_parking_time, // starting time
end_parking_time, // return value: end time
netto_parking_time, // minutes, netto
false, prepaid);
}
double minCost = tariff->getPaymentOptions(paymentOptionIndex).pop_min_price;
if (cost < minCost) {
calcState.setDesc(QString("minCost=%1, cost=%2").arg(minCost, cost));
return calcState.set(CalcState::State::BELOW_MIN_PARKING_PRICE);
}
// DEBUG
qCritical() << " end_parking_time: " << end_parking_time;
qCritical() << " -> calculated cost (netto): " << cost;
price->brutto = price->vat = price->vat_percentage = 0;
price->units = cost;
price->netto = cost;
} else {
return calcState.set(CalcState::State::INVALID_START_DATE);
}
return calcState.set(CalcState::State::SUCCESS);
}
CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket(
parking_tariff_t *tariff,
time_t start_parking_time,
double price,
QString &duration) {
CalcState calcState;
QDate const d(1970, 1, 1);
QTime const t(0, 0, 0);
QDateTime start(d, t, Qt::UTC);
start = start.toLocalTime().addSecs(start_parking_time * 60);
if (start.isValid()) {
QString cs = start.toString(Qt::ISODate);
// DEBUG
qCritical() << "compute_duration_for_parking_ticket(): ";
qCritical() << " start (cs): " << cs;
qCritical() << " price: " << price;
duration = Calculator::GetInstance().GetDurationFromCost(tariff,
tariff->getPaymentOptions().pop_payment_method_id,
cs.toLocal8Bit().constData(),
price, false, true).c_str();
QDateTime d = QDateTime::fromString(duration, Qt::ISODate);
if (!d.isValid()) {
calcState.setDesc(QString("ticketEndTime=%1").arg(duration));
return calcState.set(CalcState::State::WRONG_ISO_TIME_FORMAT);
}
} else {
return calcState.set(CalcState::State::INVALID_START_DATE);
}
return calcState.set(CalcState::State::SUCCESS);
}
CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket(
parking_tariff_t *tariff,
QDateTime const &start_parking_time,
double price,
QDateTime &ticketEndTime)
{
CalcState calcState;
if (start_parking_time.isValid()) {
QString cs = start_parking_time.toString(Qt::ISODate);
QString endTime = Calculator::GetInstance().GetDurationFromCost(
tariff,
tariff->getPaymentOptions().pop_payment_method_id,
cs.toLocal8Bit().constData(),
price, false, true).c_str();
if (endTime == CalcState::SUCCESS) {
calcState.setDesc(QString("SUCCESS"));
calcState.setStatus(endTime);
} else
if (endTime == CalcState::ERROR_PARSING_ZONE_NR) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::ERROR_LOADING_TARIFF) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::ERROR_PARSING_TARIFF) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::NEGATIVE_PARKING_TIME) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::INVALID_START_DATE) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::WRONG_PARAM_VALUES) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::WRONG_ISO_TIME_FORMAT) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::ABOVE_MAX_PARKING_TIME) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::BELOW_MIN_PARKING_TIME) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::BELOW_MIN_PARKING_PRICE) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::ABOVE_MAX_PARKING_PRICE) {
calcState.setDesc(CalcState::ABOVE_MAX_PARKING_PRICE);
calcState.setStatus(CalcState::ABOVE_MAX_PARKING_PRICE);
return calcState;
} else
if (endTime == CalcState::OVERPAID) {
calcState.setDesc(CalcState::OVERPAID);
calcState.setStatus(CalcState::OVERPAID);
return calcState;
} else
if (endTime == CalcState::OUTSIDE_ALLOWED_PARKING_TIME) {
calcState.setStatus(endTime);
return calcState;
} else {
ticketEndTime = QDateTime::fromString(endTime,Qt::ISODate);
// DEBUG
//qCritical() << "compute_duration_for_parking_ticket(): ";
//qCritical() << " endTime: " << endTime;
//qCritical() << " ticketEndTime: " << ticketEndTime;
if (!ticketEndTime.isValid()) {
calcState.setDesc(QString("ticketEndTime=%1").arg(endTime));
return calcState.set(CalcState::State::WRONG_ISO_TIME_FORMAT);
}
}
} else {
return calcState.set(CalcState::State::INVALID_START_DATE);
}
return calcState.set(CalcState::State::SUCCESS);
}
CalcState CALCULATE_LIBRARY_API compute_duration_for_daily_ticket(parking_tariff_t *tariff, QDateTime const &start_parking_time, QDateTime &ticketEndTime)
{
CalcState calcState;
if (start_parking_time.isValid()) {
ticketEndTime = Calculator::GetInstance().GetDailyTicketDuration(tariff,
start_parking_time,
tariff->getPaymentOptions().pop_payment_method_id,
false); // carry over
// DEBUG
qCritical() << "compute_duration_for_daily_ticket(): ";
qCritical() << " ticketEndTime: " << ticketEndTime;
if (!ticketEndTime.isValid()) {
calcState.setDesc(QString("ticketEndTime=%1").arg(ticketEndTime.toString(Qt::ISODate)));
return calcState.set(CalcState::State::WRONG_ISO_TIME_FORMAT);
}
} else {
return calcState.set(CalcState::State::INVALID_START_DATE);
}
return calcState.set(CalcState::State::SUCCESS);
}
CalcState CALCULATE_LIBRARY_API compute_price_for_daily_ticket(
parking_tariff_t *tariff,
QDateTime const &startDatetime,
QDateTime &endDatetime,
PERMIT_TYPE permitType,
struct price_t *price) {// return value
CalcState calcState;
if (startDatetime.isValid()) {
if (std::optional<struct price_t> p =
Calculator::GetInstance().GetDailyTicketPrice(tariff,
startDatetime,
endDatetime,
permitType)) {
*price = p.value();
}
} else {
return calcState.set(CalcState::State::INVALID_START_DATE);
}
return calcState.set(CalcState::State::SUCCESS);
}

File diff suppressed because it is too large Load Diff

@ -115,8 +115,8 @@ QDateTime Calculator::GetDailyTicketDuration(Configuration* cfg, const QDateTime
/// <inheritdoc/> /// <inheritdoc/>
std::string Calculator::GetDurationFromCost(Configuration* cfg, std::string Calculator::GetDurationFromCost(Configuration* cfg,
uint8_t payment_option, uint8_t payment_option,
char const* start_datetime, // given in local time char const *startDatetimePassed, // given in local time
double price, double cost,
bool nextDay, bool nextDay,
bool prepaid) bool prepaid)
{ {
@ -124,14 +124,14 @@ std::string Calculator::GetDurationFromCost(Configuration* cfg,
Q_UNUSED(nextDay); Q_UNUSED(nextDay);
// Get input date // Get input date
QDateTime inputDate = QDateTime::fromString(start_datetime,Qt::ISODate); QDateTime inputDate = QDateTime::fromString(startDatetimePassed,Qt::ISODate);
static const PaymentMethod paymentMethodId = Utilities::getPaymentMethodId(cfg); static const PaymentMethod paymentMethodId = Utilities::getPaymentMethodId(cfg);
if (paymentMethodId == PaymentMethod::Steps) { if (paymentMethodId == PaymentMethod::Steps) {
if (tariffIs24_7(cfg)) { if (tariffIs24_7(cfg)) {
// use tariff with structure as for instance Schoenau, Koenigsee: // use tariff with structure as for instance Schoenau, Koenigsee:
// without given YearPeriod, SpecialDays and SpecialDaysWorktime // without given YearPeriod, SpecialDays and SpecialDaysWorktime
inputDate = inputDate.addSecs(GetDurationForPrice(cfg, price) * 60); inputDate = inputDate.addSecs(GetDurationForPrice(cfg, cost) * 60);
return inputDate.toString(Qt::ISODate).toStdString(); return inputDate.toString(Qt::ISODate).toStdString();
} else { } else {
if (Utilities::IsYearPeriodActive(cfg, inputDate)) { if (Utilities::IsYearPeriodActive(cfg, inputDate)) {
@ -147,9 +147,226 @@ std::string Calculator::GetDurationFromCost(Configuration* cfg,
return ""; return "";
} }
} }
} else
if (paymentMethodId == PaymentMethod::Progressive) {
// started with Neuhauser, Kirchdorf: merge into main algo. later
// for now try out some ideas
// started with Neuhauser, Kirchdorf: merge into main algo. later
// for now try out some ideas
static const bool carryOverNotSet = Utilities::isCarryOverNotSet(cfg, paymentMethodId);
static const uint minParkingPrice = Utilities::getMinimalParkingPrice(cfg, paymentMethodId);
static const uint maxParkingPrice = Utilities::getMaximalParkingPrice(cfg, paymentMethodId);
if (cost < minParkingPrice) {
qCritical() << QString("ERROR: COST < MIN_PARKING_PRICE (%1 < %2)").arg(cost).arg(minParkingPrice);
return QDateTime().toString(Qt::ISODate).toStdString();
}
if (cost > maxParkingPrice) {
qCritical() << QString("WARN: COST > MAX_PARKING_PRICE (%1 > %2)").arg(cost).arg(maxParkingPrice);
cost = maxParkingPrice;
}
Q_ASSERT_X(carryOverNotSet, __func__, "CARRYOVER SET (FOR KIRCHDORF)");
Q_ASSERT_X(prepaid, __func__, "PREPAID NOT SET (FOR KIRCHDORF)");
QDateTime start_datetime = QDateTime::fromString(QString(startDatetimePassed), Qt::ISODate);
QDateTime start = start_datetime;
QDateTime end_datetime = QDateTime();
int weekdayId = -1;
int weekdayIdLast = -1;
int durationMinutes = Utilities::getMaximalParkingTime(cfg, paymentMethodId);
int durationMinutesBrutto = 0;
QDateTime current = start;
int days = 7;
while (--days > 0) {
weekdayId = current.date().dayOfWeek();
weekdayIdLast = weekdayId; // TODO: some end condition in json-file
while (cfg->WeekDaysWorktime.count(weekdayId) == 0) {
current = current.addDays(1);
weekdayId = current.date().dayOfWeek();
if (weekdayId == weekdayIdLast) {
qCritical() << "ERROR: NO VALID WORKDAY-TIMES DEFINED";
return QDateTime().toString(Qt::ISODate).toStdString();
}
}
using WTIterator = std::multimap<int, ATBWeekDaysWorktime>::const_iterator;
std::pair<WTIterator, WTIterator> p = cfg->WeekDaysWorktime.equal_range(weekdayId);
QTime to = QTime(0, 0, 0);
for (WTIterator itr = p.first; itr != p.second; ++itr) {
QTime const &t = Utilities::WeekDaysWorkTimeUntil(itr);
if (to < t) {
to = t;
}
}
if (current.time() >= to) {
if (carryOverNotSet) {
return end_datetime.toString(Qt::ISODate).toStdString();
} else {
QDateTime const dt = start;
start = start.addDays(1);
start.setTime(QTime(0, 0, 0));
durationMinutesBrutto += dt.secsTo(start) / 60;
current = start;
}
} else {
break;
}
}
int durationMinutesNetto = 0;
uint price = 0;
if (carryOverNotSet) {
int range = 0;
int minsToCarryOver = 0; // from one work-time to the other on the same day
int minsUsed = 0;
QDateTime lastCurrent = QDateTime();
auto timeRangeIt = cfg->TimeRange.cbegin();
for (; timeRangeIt != cfg->TimeRange.cend(); ++timeRangeIt) {
using WTIterator = std::multimap<int, ATBWeekDaysWorktime>::const_iterator;
std::pair<WTIterator, WTIterator> p = cfg->WeekDaysWorktime.equal_range(weekdayId);
for (WTIterator itr = p.first; itr != p.second; ++itr) {
++range;
QTime const &from = Utilities::WeekDaysWorkTimeFrom(itr);
QTime const &to = Utilities::WeekDaysWorkTimeUntil(itr);
Q_ASSERT_X(from < to, __func__, "MISCONFIGURED WORK-TIMES");
if (current.time() >= to) {
continue; // try to use next available work-time
} else
if (current.time() <= from) {
if (prepaid) {
lastCurrent = current;
current.setTime(from); // move current forward (range==1),
// as prepaid is set
uint const minutesMoved = lastCurrent.secsTo(current) / 60;
durationMinutesBrutto += minutesMoved;
if (range == 1) {
start_datetime = current;
}
}
}
while (timeRangeIt != cfg->TimeRange.cend()) {
ATBTimeRange timeRange = timeRangeIt->second;
timeRange.computeQTimes(current.time());
int duration = timeRange.time_range_to_in_minutes_from_start -
timeRange.time_range_from_in_minutes_from_start;
if (minsUsed > 0) {
duration -= minsUsed;
minsUsed = 0;
}
if (current.addSecs(duration * 60).time() <= to) {
if (minsToCarryOver > 0) { // the price for this time range
// has been is paid already
durationMinutes -= duration;
durationMinutesNetto += duration;
durationMinutesBrutto += duration;
current = current.addSecs(duration*60);
minsToCarryOver = 0;
} else {
for(const auto &x: cfg->PaymentRate) {
ATBPaymentRate const rate = x.second;
if (rate.pra_payment_unit_id == timeRange.time_range_payment_type_id) {
price += (uint)rate.pra_price;
if (price >= maxParkingPrice) {
price = maxParkingPrice;
}
durationMinutes -= duration;
durationMinutesNetto += duration;
durationMinutesBrutto += duration;
current = current.addSecs(duration * 60);
if (price >= cost) {
end_datetime = current;
return end_datetime.toString(Qt::ISODate).toStdString();
}
break;
}
}
}
if (durationMinutes <= 0) {
end_datetime = current;
return end_datetime.toString(Qt::ISODate).toStdString();
}
++timeRangeIt;
} else {
lastCurrent = current;
current.setTime(to);
minsUsed = lastCurrent.secsTo(current) / 60;
// mod duration: possibly discard some minutes in
// the next time-range
if (durationMinutes >= minsUsed) {
minsToCarryOver = durationMinutes - minsUsed;
}
durationMinutes -= minsUsed;
durationMinutesNetto += minsUsed;
durationMinutesBrutto += minsUsed;
if (minsUsed > 0) {
for(const auto &x: cfg->PaymentRate) {
ATBPaymentRate const rate = x.second;
if (rate.pra_payment_unit_id == timeRange.time_range_payment_type_id) {
price += (uint)rate.pra_price;
if (price >= maxParkingPrice) {
price = maxParkingPrice;
}
if (price >= cost) {
end_datetime = current;
// return end_datetime.toString(Qt::ISODate).toStdString();
}
break;
}
}
}
break;
}
}
}
end_datetime = start.addSecs(durationMinutesBrutto * 60);
return end_datetime.toString(Qt::ISODate).toStdString();
}
}
end_datetime = QDateTime();
return end_datetime.toString(Qt::ISODate).toStdString();
} }
Ticket t = private_GetDurationFromCost(cfg, inputDate, price, prepaid); Ticket t = private_GetDurationFromCost(cfg, inputDate, cost, prepaid);
// qCritical().noquote() << t; // qCritical().noquote() << t;
@ -279,9 +496,11 @@ double Calculator::GetCostFromDuration(Configuration* cfg,
end_datetime.setTime(cs.getAllowedTimeRange().getTimeUntil()); end_datetime.setTime(cs.getAllowedTimeRange().getTimeUntil());
return cost; return cost;
} }
} else {
// it might be that in such a case even prepaid ("vorkauf")
// is not allowed at any moment
} }
qCritical() << "(" << __func__ << ":" << __LINE__ << ")" << "NOT YET IMPLEMENTED";
qCritical() << __PRETTY_FUNCTION__ << "NOT YET IMPLEMENTED";
end_datetime = QDateTime(); end_datetime = QDateTime();
return 0; return 0;
} }
@ -299,34 +518,18 @@ double Calculator::GetCostFromDuration(Configuration* cfg,
QDateTime start = start_datetime; QDateTime start = start_datetime;
#define DEBUG 0
#if DEBUG==1
qCritical() << "start" << start.toString(Qt::ISODate) << durationMinutes;
#endif
int weekdayId = -1; int weekdayId = -1;
int weekdayIdLast = -1; int weekdayIdLast = -1;
int timeRanges = 0;
int durationMinutesBrutto = 0; int durationMinutesBrutto = 0;
QDateTime current = start; QDateTime current = start;
//if ((durationMinutes % 5) != 0) {
// qCritical() << "ERROR DURATION (" << durationMinutes
// << ") NOT A MULTIPLE Of 5";
//}
int days = 7; int days = 7;
while (--days > 0) { while (--days > 0) {
#if DEBUG==1
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "start" << start.toString(Qt::ISODate)
<< "current" << current.toString(Qt::ISODate);
#endif
weekdayId = current.date().dayOfWeek(); weekdayId = current.date().dayOfWeek();
weekdayIdLast = weekdayId; // TODO: some end condition in json-file weekdayIdLast = weekdayId; // TODO: some end condition in json-file
while ((timeRanges = cfg->WeekDaysWorktime.count(weekdayId)) == 0) { while (cfg->WeekDaysWorktime.count(weekdayId) == 0) {
current = current.addDays(1); current = current.addDays(1);
weekdayId = current.date().dayOfWeek(); weekdayId = current.date().dayOfWeek();
if (weekdayId == weekdayIdLast) { if (weekdayId == weekdayIdLast) {
@ -335,11 +538,6 @@ double Calculator::GetCostFromDuration(Configuration* cfg,
} }
} }
#if DEBUG==1
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "current" << current.toString(Qt::ISODate);
#endif
using WTIterator = std::multimap<int, ATBWeekDaysWorktime>::const_iterator; using WTIterator = std::multimap<int, ATBWeekDaysWorktime>::const_iterator;
std::pair<WTIterator, WTIterator> p = cfg->WeekDaysWorktime.equal_range(weekdayId); std::pair<WTIterator, WTIterator> p = cfg->WeekDaysWorktime.equal_range(weekdayId);
@ -347,235 +545,169 @@ double Calculator::GetCostFromDuration(Configuration* cfg,
for (WTIterator itr = p.first; itr != p.second; ++itr) { for (WTIterator itr = p.first; itr != p.second; ++itr) {
QTime const &t = Utilities::WeekDaysWorkTimeUntil(itr); QTime const &t = Utilities::WeekDaysWorkTimeUntil(itr);
#if DEBUG==1
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "current" << current.time().toString(Qt::ISODate)
<< "t" << t.toString(Qt::ISODate)
<< "to" << to.toString(Qt::ISODate);
#endif
if (to < t) { if (to < t) {
to = t; to = t;
} }
} }
if (current.time() >= to) { if (current.time() >= to) {
QDateTime const dt = start; if (carryOverNotSet) {
start = start.addDays(1); end_datetime = start;
start.setTime(QTime(0, 0, 0)); return 0;
} else {
QDateTime const dt = start;
start = start.addDays(1);
start.setTime(QTime(0, 0, 0));
durationMinutesBrutto += dt.secsTo(start) / 60; durationMinutesBrutto += dt.secsTo(start) / 60;
current = start; current = start;
}
} else { } else {
#if DEBUG==1
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "current" << current.toString(Qt::ISODate)
<< "durationMinutesBrutto" << durationMinutesBrutto;
#endif
break; break;
} }
} }
#if DEBUG==1
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "timeRanges" << timeRanges << weekdayId
<< "durationMinutesBrutto" << durationMinutesBrutto
<< "start" << start.toString(Qt::ISODate)
<< "current" << current.toString(Qt::ISODate);
#endif
int durationMinutesNetto = 0; int durationMinutesNetto = 0;
uint price = 0; uint price = 0;
if (carryOverNotSet) { if (carryOverNotSet) {
int range = 0; int range = 0;
int minsToCarryOver = 0; // from one work-time to the other on the same day int minsToCarryOver = 0; // from one work-time to the other on the same day
int minsUsed = 0;
QDateTime lastCurrent = QDateTime(); QDateTime lastCurrent = QDateTime();
auto timeRangeIt = cfg->TimeRange.cbegin(); using WTIterator = std::multimap<int, ATBWeekDaysWorktime>::const_iterator;
for (; timeRangeIt != cfg->TimeRange.cend(); ++timeRangeIt) { std::pair<WTIterator, WTIterator> p = cfg->WeekDaysWorktime.equal_range(weekdayId);
using WTIterator = std::multimap<int, ATBWeekDaysWorktime>::const_iterator;
std::pair<WTIterator, WTIterator> p = cfg->WeekDaysWorktime.equal_range(weekdayId);
for (WTIterator itr = p.first; itr != p.second; ++itr) { for (WTIterator itr = p.first; itr != p.second; ++itr) {
++range; ++range;
QTime const &from = Utilities::WeekDaysWorkTimeFrom(itr); QTime const &from = Utilities::WeekDaysWorkTimeFrom(itr);
QTime const &to = Utilities::WeekDaysWorkTimeUntil(itr); QTime const &to = Utilities::WeekDaysWorkTimeUntil(itr);
Q_ASSERT_X(from < to, __func__, "MISCONFIGURED WORK-TIMES"); Q_ASSERT_X(from < to, __func__, "MISCONFIGURED WORK-TIMES");
if (current.time() >= to) {
continue; // try to use next available work-time
} else
if (current.time() <= from) {
if (prepaid) {
lastCurrent = current;
current.setTime(from); // move current forward (range==1),
// as prepaid is set
uint const minutesMoved = lastCurrent.secsTo(current) / 60;
durationMinutesBrutto += minutesMoved;
if (current.time() >= to) { if (range == 1) {
#if DEBUG==1 start_datetime = current;
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "current" << current.toString(Qt::ISODate)
<< "from" << from.toString(Qt::ISODate)
<< "to" << to.toString(Qt::ISODate);
#endif
continue; // try to use next available work-time
} else
if (current.time() <= from) {
if (prepaid) {
lastCurrent = current;
current.setTime(from); // move current forward (range==1),
// as prepaid is set
uint const minutesMoved = lastCurrent.secsTo(current) / 60;
#if DEBUG==1
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "current" << current.toString(Qt::ISODate)
<< "lastCurrent" << lastCurrent.toString(Qt::ISODate)
<< "minutesMoved" << minutesMoved
<< "durationMinutes" << durationMinutes;
#endif
durationMinutesBrutto += minutesMoved;
if (range == 1) {
start_datetime = current;
}
} }
} }
}
#if DEBUG==1 for (auto timeRangeIt = cfg->TimeRange.cbegin(); timeRangeIt != cfg->TimeRange.cend(); ++timeRangeIt) {
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "from" << from.toString(Qt::ISODate) ATBTimeRange timeRange = timeRangeIt->second;
<< "to" << to.toString(Qt::ISODate)
timeRange.computeQTimes(current.time());
int duration = timeRange.time_range_to_in_minutes_from_start -
timeRange.time_range_from_in_minutes_from_start;
qCritical() << __func__ << ":" << __LINE__
<< "current" << current.toString(Qt::ISODate) << "current" << current.toString(Qt::ISODate)
<< "durationMinutes" << durationMinutes; << "duration" << duration
#endif << "minsUsed" << minsUsed
<< "minsToCarryOver" << minsToCarryOver;
while (timeRangeIt != cfg->TimeRange.cend()) {
ATBTimeRange timeRange = timeRangeIt->second;
timeRange.computeQTimes(current.time()); //if (minsUsed > 0) {
// duration -= minsUsed;
// minsUsed = 0;
//}
int duration = timeRange.time_range_to_in_minutes_from_start - if (current.addSecs(duration * 60).time() <= to) {
timeRange.time_range_from_in_minutes_from_start; if (minsToCarryOver > 0) { // the price for this time range
// has been is paid already
#if DEBUG==1 if (minsUsed == 0) {
qCritical() << "(" << __func__ << ":" << __LINE__ << ")" for(const auto &x: cfg->PaymentRate) {
<< "duration" << duration << timeRange.time_range_id ATBPaymentRate const rate = x.second;
<< "current" << current.toString(Qt::ISODate) if (rate.pra_payment_unit_id == timeRange.time_range_payment_type_id) {
<< "minsToCarryOver" << minsToCarryOver
<< "durationMinutes" << durationMinutes;
#endif
if (current.addSecs(duration * 60).time() <= to) {
for(const auto &x: cfg->PaymentRate) {
ATBPaymentRate const rate = x.second;
if (rate.pra_payment_unit_id == timeRange.time_range_payment_type_id) {
if (minsToCarryOver > 0) {
durationMinutes -= minsToCarryOver;
durationMinutesNetto += minsToCarryOver;
durationMinutesBrutto += minsToCarryOver;
current = current.addSecs(minsToCarryOver*60);
minsToCarryOver = 0;
#if DEBUG==1
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "durationMinutes" << durationMinutes
<< "durationMinutesNetto" << durationMinutesNetto
<< "durationMinutesBrutto" << durationMinutesBrutto
<< "current" << current.toString(Qt::ISODate);
#endif
} else {
price += (uint)rate.pra_price; price += (uint)rate.pra_price;
durationMinutes -= duration; durationMinutes -= duration;
durationMinutesNetto += duration; durationMinutesNetto += duration;
durationMinutesBrutto += duration; durationMinutesBrutto += duration;
#if DEBUG==1
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "duration" << duration
<< "durationMinutes" << durationMinutes
<< "durationMinutesNetto" << durationMinutesNetto
<< "durationMinutesBrutto" << durationMinutesBrutto;
#endif
current = current.addSecs(duration * 60); current = current.addSecs(duration * 60);
#if DEBUG==1 if (durationMinutes <= 0) {
qCritical() << "(" << __func__ << ":" << __LINE__ << ")" end_datetime = current;
<< "current" << current.toString(Qt::ISODate) return price;
<< "price" << price; }
#endif
}
break;
}
}
if (durationMinutes <= 0) {
end_datetime = current;
#if DEBUG==1
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "duration" << durationMinutesNetto << ", price" << price
<< current.toString(Qt::ISODate)
<< end_datetime.toString(Qt::ISODate);
#endif
return price;
}
++timeRangeIt;
} else {
lastCurrent = current;
current.setTime(to);
int const minsLeft = lastCurrent.secsTo(current) / 60;
// mod duration: possibly discard some minutes in
// the next time-range
minsToCarryOver = (durationMinutes - minsLeft) % duration;
durationMinutes -= minsLeft;
durationMinutesNetto += minsLeft;
durationMinutesBrutto += minsLeft;
#if DEBUG==1
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "lastCurrent" << lastCurrent.toString(Qt::ISODate)
<< "current" << current.toString(Qt::ISODate)
<< "minsLeft" << minsLeft;
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "duration" << duration
<< "durationMinutes" << durationMinutes
<< "durationMinutesNetto" << durationMinutesNetto
<< "durationMinutesBrutto" << durationMinutesBrutto
<< "minsToCarryOver" << minsToCarryOver;
#endif
if (minsLeft > 0) {
for(const auto &x: cfg->PaymentRate) {
ATBPaymentRate const rate = x.second;
if (rate.pra_payment_unit_id == timeRange.time_range_payment_type_id) {
price += (uint)rate.pra_price;
#if DEBUG==1
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "price" << price;
#endif
break; break;
} }
} }
} else {
durationMinutes -= duration;
durationMinutesNetto += duration;
durationMinutesBrutto += duration;
current = current.addSecs(duration*60);
minsToCarryOver = 0;
} }
} else {
for(const auto &x: cfg->PaymentRate) {
ATBPaymentRate const rate = x.second;
if (rate.pra_payment_unit_id == timeRange.time_range_payment_type_id) {
price += (uint)rate.pra_price;
break; durationMinutes -= duration;
durationMinutesNetto += duration;
durationMinutesBrutto += duration;
current = current.addSecs(duration * 60);
break;
}
}
} }
if (durationMinutes <= 0) {
end_datetime = current;
return price;
}
//++timeRangeIt;
} else {
lastCurrent = current;
current.setTime(to);
minsUsed = lastCurrent.secsTo(current) / 60;
// mod duration: possibly discard some minutes in
// the next time-range
if (durationMinutes >= minsUsed) {
minsToCarryOver = durationMinutes - minsUsed;
}
durationMinutes -= minsUsed;
durationMinutesNetto += minsUsed;
durationMinutesBrutto += minsUsed;
if (minsUsed > 0) {
for(const auto &x: cfg->PaymentRate) {
ATBPaymentRate const rate = x.second;
if (rate.pra_payment_unit_id == timeRange.time_range_payment_type_id) {
price += (uint)rate.pra_price;
break;
}
}
}
// break;
} }
} } // for (WTIterator itr = p.first; itr != p.second; ++itr) {
end_datetime = start.addSecs(durationMinutesBrutto * 60); end_datetime = start.addSecs(durationMinutesBrutto * 60);
#if DEBUG==1
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "duration" << durationMinutesNetto
<< ", price" << std::max(price, minParkingPrice)
<< start.toString(Qt::ISODate)
<< end_datetime.toString(Qt::ISODate);
#endif
return std::max(price, minParkingPrice); return std::max(price, minParkingPrice);
} }
} }
@ -1072,6 +1204,8 @@ QList<int> Calculator::GetTimeSteps(Configuration *cfg) const {
int const pop_carry_over = cfg->getPaymentOptions().pop_carry_over; int const pop_carry_over = cfg->getPaymentOptions().pop_carry_over;
int const pop_time_step_config = cfg->getPaymentOptions().pop_time_step_config; int const pop_time_step_config = cfg->getPaymentOptions().pop_time_step_config;
static PaymentMethod const paymentMethodId = Utilities::getPaymentMethodId(cfg);
qCritical() << __func__ << ":" << __LINE__ << " start parking time:" << start.toString(Qt::ISODate); qCritical() << __func__ << ":" << __LINE__ << " start parking time:" << start.toString(Qt::ISODate);
qCritical() << __func__ << ":" << __LINE__ << " payment option id:" << pop_id; qCritical() << __func__ << ":" << __LINE__ << " payment option id:" << pop_id;
qCritical() << __func__ << ":" << __LINE__ << "payment option carry over:" << pop_carry_over; qCritical() << __func__ << ":" << __LINE__ << "payment option carry over:" << pop_carry_over;
@ -1079,63 +1213,71 @@ QList<int> Calculator::GetTimeSteps(Configuration *cfg) const {
if (pop_time_step_config == (int)ATBTimeStepConfig::TimeStepConfig::DYNAMIC) { if (pop_time_step_config == (int)ATBTimeStepConfig::TimeStepConfig::DYNAMIC) {
//qCritical() << __PRETTY_FUNCTION__ << "payment option time step config:" << "TimeStepConfig::DYNAMIC"; //qCritical() << __PRETTY_FUNCTION__ << "payment option time step config:" << "TimeStepConfig::DYNAMIC";
uint16_t timeStepCompensation = 0; if (paymentMethodId == PaymentMethod::Progressive) { // e.g. neuhauser kirchdorf (743)
std::size_t const s = cfg->TimeRange.size();
for (std::size_t id = 1; id <= s; ++id) {
int const step = Utilities::getTimeRangeStep(cfg, id, paymentMethodId);
m_timeSteps.append(step);
}
} else {
uint16_t timeStepCompensation = 0;
if (pop_carry_over) { if (pop_carry_over) {
int const pop_carry_over_time_range_id = cfg->getPaymentOptions().pop_carry_over_time_range_id; int const pop_carry_over_time_range_id = cfg->getPaymentOptions().pop_carry_over_time_range_id;
QTime const carryOverTimeRangeFrom = cfg->TimeRange.find(pop_carry_over_time_range_id)->second.time_range_from; QTime const carryOverTimeRangeFrom = cfg->TimeRange.find(pop_carry_over_time_range_id)->second.time_range_from;
QTime const carryOverTimeRangeTo = cfg->TimeRange.find(pop_carry_over_time_range_id)->second.time_range_to; QTime const carryOverTimeRangeTo = cfg->TimeRange.find(pop_carry_over_time_range_id)->second.time_range_to;
if (carryOverTimeRangeFrom.secsTo(carryOverTimeRangeTo) <= 60) { // carry over time point, usually 00:00:00 if (carryOverTimeRangeFrom.secsTo(carryOverTimeRangeTo) <= 60) { // carry over time point, usually 00:00:00
if (carryOverTimeRangeFrom == QTime(0, 0, 0)) { if (carryOverTimeRangeFrom == QTime(0, 0, 0)) {
for (auto[itr, rangeEnd] = cfg->PaymentRate.equal_range(pop_id); itr != rangeEnd; ++itr) { for (auto[itr, rangeEnd] = cfg->PaymentRate.equal_range(pop_id); itr != rangeEnd; ++itr) {
int const durationId = itr->second.pra_payment_unit_id; int const durationId = itr->second.pra_payment_unit_id;
auto search = cfg->Duration.find(durationId); auto search = cfg->Duration.find(durationId);
if (search != cfg->Duration.end()) { if (search != cfg->Duration.end()) {
ATBDuration duration = search->second; ATBDuration duration = search->second;
if (durationId == 1) { if (durationId == 1) {
QDateTime carryOver = start; QDateTime carryOver = start;
carryOver = carryOver.addDays(1); carryOver = carryOver.addDays(1);
carryOver.setTime(QTime(0, 0, 0)); carryOver.setTime(QTime(0, 0, 0));
int const timeStep = std::ceil(start.secsTo(carryOver) / 60.0); int const timeStep = std::ceil(start.secsTo(carryOver) / 60.0);
if (timeStep < duration.pun_duration_min || timeStep > duration.pun_duration_max) { if (timeStep < duration.pun_duration_min || timeStep > duration.pun_duration_max) {
qCritical() qCritical()
<< QString("ERROR timeStep (%1) < durationMin (%2) || timeStep (%3)) > durationMax (%4)") << QString("ERROR timeStep (%1) < durationMin (%2) || timeStep (%3)) > durationMax (%4)")
.arg(timeStep).arg(duration.pun_duration_min) .arg(timeStep).arg(duration.pun_duration_min)
.arg(timeStep).arg(duration.pun_duration_max); .arg(timeStep).arg(duration.pun_duration_max);
break; break;
}
qCritical() << __PRETTY_FUNCTION__ << "configured minimal parking time:" << cfg->getPaymentOptions().pop_min_time;
// set dynamic minimal parking time
cfg->getPaymentOptions().pop_min_time = timeStep;
qCritical() << __PRETTY_FUNCTION__ << " computed minimal parking time:" << cfg->getPaymentOptions().pop_min_time;
duration.pun_duration = timeStep;
timeStepCompensation = duration.pun_duration_max - duration.pun_duration;
m_timeSteps << duration.pun_duration;
} else {
duration.pun_duration = duration.pun_duration_max - timeStepCompensation;
m_timeSteps << duration.pun_duration;;
} }
qCritical() << __PRETTY_FUNCTION__ << "configured minimal parking time:" << cfg->getPaymentOptions().pop_min_time;
// set dynamic minimal parking time cfg->Duration.erase(search);
cfg->getPaymentOptions().pop_min_time = timeStep; cfg->Duration.insert(pair<int, ATBDuration>(duration.pun_id, duration));
qCritical() << __PRETTY_FUNCTION__ << " computed minimal parking time:" << cfg->getPaymentOptions().pop_min_time; } else { // if (search != cfg->Duration.end()) {
// TODO
duration.pun_duration = timeStep;
timeStepCompensation = duration.pun_duration_max - duration.pun_duration;
m_timeSteps << duration.pun_duration;
} else {
duration.pun_duration = duration.pun_duration_max - timeStepCompensation;
m_timeSteps << duration.pun_duration;;
} }
cfg->Duration.erase(search);
cfg->Duration.insert(pair<int, ATBDuration>(duration.pun_id, duration));
} else { // if (search != cfg->Duration.end()) {
// TODO
} }
} else { // if (carryOverTimeRangeFrom == QTime(0, 0, 0)) {
// TODO
} }
} else { // if (carryOverTimeRangeFrom == QTime(0, 0, 0)) { } else { // if (carryOverTimeRangeFrom == carryOverTimeRangeTo) {
// TODO // TODO
} }
} else { // if (carryOverTimeRangeFrom == carryOverTimeRangeTo) { } else { // if (pop_carry_over) {
// TODO // TODO
} }
} else { // if (pop_carry_over) {
// TODO
} }
} else { } else {
qCritical() << __PRETTY_FUNCTION__ << "payment option time step config:" << "TimeStepConfig::STATIC"; qCritical() << __PRETTY_FUNCTION__ << "payment option time step config:" << "TimeStepConfig::STATIC";
@ -1308,6 +1450,18 @@ Calculator::GetDailyTicketPrice(Configuration* cfg,
case PERMIT_TYPE::INVALID: case PERMIT_TYPE::INVALID:
break; break;
} }
} else {
// for projects which have not defined a daily ticket in their
// tariff-files (e.g. szeged)
price.netto = cfg->getPaymentOptions().pop_daily_card_price;
qCritical() << "( GetDailyTicketPrice():" << __LINE__ << ")";
qCritical() << " start:" << startDatetime.toString(Qt::ISODate);
qCritical() << " workTime from:" << QTime::fromString(QString(wt.pwd_time_from.c_str()), Qt::ISODate);
qCritical() << " workTime to:" << QTime::fromString(QString(wt.pwd_time_to.c_str()), Qt::ISODate);
qCritical() << "daily_ticket_card_price:" << price.netto;
value = value.value_or(price);
} }
} }

File diff suppressed because it is too large Load Diff

@ -0,0 +1,5 @@
#include "tariff_global_defines.h"
int DBG_LEVEL = DBG_NOTICE;
// int DBG_LEVEL = DBG_INFORMATION;
// int DBG_LEVEL = DBG_DEBUG;

@ -1,5 +1,6 @@
#include "utilities.h" #include "utilities.h"
#include "tariff_log.h" #include "tariff_log.h"
#include "tariff_business_hours.h"
#include <QDebug> #include <QDebug>
#include <algorithm> #include <algorithm>
@ -206,7 +207,13 @@ bool Utilities::IsYearPeriodActive(Configuration const *cfg, QDateTime const &dt
dt.date().day()); dt.date().day());
QDate const s(2004, year.second.pye_start_month, year.second.pye_start_day); QDate const s(2004, year.second.pye_start_month, year.second.pye_start_day);
QDate const e(2004, year.second.pye_end_month, year.second.pye_end_day); QDate const e(2004, year.second.pye_end_month, year.second.pye_end_day);
return (d >= s && d <= e); //qCritical() << __func__ << __LINE__ << " d" << d.toString(Qt::ISODate);
//qCritical() << __func__ << __LINE__ << "start" << s.toString(Qt::ISODate);
//qCritical() << __func__ << __LINE__ << " end" << e.toString(Qt::ISODate);
if (s <= e) {
return (d >= s && d <= e);
}
return (d >= s || d <= e);
})) { })) {
qCritical() << "NO VALID YEAR PERIOD"; qCritical() << "NO VALID YEAR PERIOD";
return false; return false;
@ -214,6 +221,43 @@ bool Utilities::IsYearPeriodActive(Configuration const *cfg, QDateTime const &dt
return true; return true;
} }
std::optional<ATBPeriodYear>
Utilities::GetYearPeriodActive(Configuration const *cfg, QDateTime const &currentDateTime) {
ATBPeriodYear period;
std::optional<ATBPeriodYear> value;
for (multimap<int, ATBPeriodYear>::const_iterator it = cfg->YearPeriod.cbegin();
it != cfg->YearPeriod.cend();
++it) {
QDate const s(currentDateTime.date().year(), it->second.pye_start_month, it->second.pye_start_day);
QDate const e(currentDateTime.date().year(), it->second.pye_end_month, it->second.pye_end_day);
QDateTime start(currentDateTime);
QDateTime end(currentDateTime);
start.setDate(s);
end.setDate(e);
if (start.date().dayOfYear() < end.date().dayOfYear()) {
// start and end in the same year
if (currentDateTime.date().dayOfYear() >= start.date().dayOfYear() &&
currentDateTime.date().dayOfYear() <= end.date().dayOfYear()) {
value = value.value_or(it->second);
break;
}
} else {
if (currentDateTime.date().dayOfYear() >= start.date().dayOfYear() ||
currentDateTime.date().dayOfYear() <= end.date().dayOfYear()) {
value = value.value_or(it->second);
break;
}
}
}
return value;
}
/// <inheritdoc/> /// <inheritdoc/>
bool Utilities::CheckSpecialDay(Configuration* cfg, const char* currentDateTimeStr, int* specialDayId, double* specialDayPrice) bool Utilities::CheckSpecialDay(Configuration* cfg, const char* currentDateTimeStr, int* specialDayId, double* specialDayPrice)
{ {
@ -260,7 +304,7 @@ bool Utilities::CheckSpecialDay(Configuration* cfg, const char* currentDateTimeS
//cout << "CheckSpecialDay() => Month is in range between start and end" << endl; //cout << "CheckSpecialDay() => Month is in range between start and end" << endl;
if ((current_tm.tm_mday >= start_tm.tm_mday) && (current_tm.tm_mday <= end_tm.tm_mday)) if ((current_tm.tm_mday >= start_tm.tm_mday) && (current_tm.tm_mday <= end_tm.tm_mday))
{ {
LOG_DEBUG("CheckSpecialDay() => SPECIAL DAY"); //LOG_DEBUG("CheckSpecialDay() => SPECIAL DAY");
*specialDayId = spec_days_itr->second.ped_id; *specialDayId = spec_days_itr->second.ped_id;
*specialDayPrice = cfg->SpecialDaysWorktime.find(*specialDayId)->second.pedwt_price; *specialDayPrice = cfg->SpecialDaysWorktime.find(*specialDayId)->second.pedwt_price;
return true; return true;
@ -275,7 +319,7 @@ bool Utilities::CheckSpecialDay(Configuration* cfg, const char* currentDateTimeS
//cout << "CheckSpecialDay() => Month is in range between start and end" << endl; //cout << "CheckSpecialDay() => Month is in range between start and end" << endl;
if ((current_tm.tm_mday >= start_tm.tm_mday) && (current_tm.tm_mday <= end_tm.tm_mday)) if ((current_tm.tm_mday >= start_tm.tm_mday) && (current_tm.tm_mday <= end_tm.tm_mday))
{ {
LOG_DEBUG("CheckSpecialDay() => SPECIAL DAY"); //LOG_DEBUG("CheckSpecialDay() => SPECIAL DAY");
*specialDayId = spec_days_itr->second.ped_id; *specialDayId = spec_days_itr->second.ped_id;
*specialDayPrice = cfg->SpecialDaysWorktime.find(*specialDayId)->second.pedwt_price; *specialDayPrice = cfg->SpecialDaysWorktime.find(*specialDayId)->second.pedwt_price;
return true; return true;
@ -317,7 +361,7 @@ bool Utilities::CheckSpecialDay(Configuration const *cfg,
continue; continue;
} }
} }
qDebug() << "CheckSpecialDay() => SPECIAL DAY"; //qDebug() << "CheckSpecialDay() => SPECIAL DAY";
*specialDayId = spec_days_itr->second.ped_id; *specialDayId = spec_days_itr->second.ped_id;
*specialDayPrice = cfg->SpecialDaysWorktime.find(*specialDayId)->second.pedwt_price; *specialDayPrice = cfg->SpecialDaysWorktime.find(*specialDayId)->second.pedwt_price;
return true; return true;
@ -333,19 +377,27 @@ QTime Utilities::SpecialDaysWorkTimeFrom(Configuration const *cfg, int specialDa
return QTime::fromString(cfg->SpecialDaysWorktime.find(specialDayId)->second.pedwt_time_from.c_str(), Qt::ISODate); return QTime::fromString(cfg->SpecialDaysWorktime.find(specialDayId)->second.pedwt_time_from.c_str(), Qt::ISODate);
} }
QTime Utilities::SpecialDaysWorkTimeFrom(Configuration::SpecialDaysWorktimeType::const_iterator const &it) {
return QTime::fromString(it->second.pedwt_time_from.c_str(), Qt::ISODate);
}
QTime Utilities::SpecialDaysWorkTimeUntil(Configuration::SpecialDaysWorktimeType::const_iterator const &it) {
return QTime::fromString(it->second.pedwt_time_to.c_str(), Qt::ISODate);
}
QTime Utilities::SpecialDaysWorkTimeUntil(Configuration const *cfg, int specialDayId) { QTime Utilities::SpecialDaysWorkTimeUntil(Configuration const *cfg, int specialDayId) {
return QTime::fromString(cfg->SpecialDaysWorktime.find(specialDayId)->second.pedwt_time_to.c_str(), Qt::ISODate); return QTime::fromString(cfg->SpecialDaysWorktime.find(specialDayId)->second.pedwt_time_to.c_str(), Qt::ISODate);
} }
QTime Utilities::WeekDaysWorkTimeFrom(std::multimap<int, ATBWeekDaysWorktime>::const_iterator itr) { QTime Utilities::WeekDaysWorkTimeFrom(std::multimap<int, ATBWeekDaysWorktime>::const_iterator const &itr) {
return QTime::fromString(itr->second.pwd_time_from.c_str(), Qt::ISODate); return QTime::fromString(itr->second.pwd_time_from.c_str(), Qt::ISODate);
} }
QTime Utilities::WeekDaysWorkTimeUntil(std::multimap<int, ATBWeekDaysWorktime>::const_iterator itr) { QTime Utilities::WeekDaysWorkTimeUntil(std::multimap<int, ATBWeekDaysWorktime>::const_iterator const &itr) {
return QTime::fromString(itr->second.pwd_time_to.c_str(), Qt::ISODate); return QTime::fromString(itr->second.pwd_time_to.c_str(), Qt::ISODate);
} }
int Utilities::WeekDayId(std::multimap<int, ATBWeekDaysWorktime>::const_iterator itr) { int Utilities::WeekDayId(std::multimap<int, ATBWeekDaysWorktime>::const_iterator const &itr) {
return itr->second.pwd_period_day_in_week_id; return itr->second.pwd_period_day_in_week_id;
} }
@ -375,6 +427,8 @@ PaymentMethod Utilities::getPaymentMethodId(Configuration const *cfg) {
return PaymentMethod::Degressive; return PaymentMethod::Degressive;
case PaymentMethod::Progressive: case PaymentMethod::Progressive:
return PaymentMethod::Progressive; return PaymentMethod::Progressive;
case PaymentMethod::Unified:
return PaymentMethod::Unified;
} }
} }
@ -397,6 +451,21 @@ uint32_t Utilities::getMaximalParkingPrice(Configuration const *cfg, PaymentMeth
return std::max((int)cfg->PaymentOption.find(methodId)->second.pop_max_price, 0); return std::max((int)cfg->PaymentOption.find(methodId)->second.pop_max_price, 0);
} }
uint32_t Utilities::getDailyTicketCardPrice(Configuration const *cfg, PaymentMethod methodId) {
return std::max((int)cfg->PaymentOption.find(methodId)->second.pop_daily_card_price, 0);
}
uint32_t Utilities::getTimeRangeStep(Configuration const *cfg, int step, PaymentMethod methodId) {
if (methodId == PaymentMethod::Progressive) {
Configuration::TimeRangeType::const_iterator it = cfg->TimeRange.find(step);
if (it != cfg->TimeRange.cend()) {
return std::max((int)(it->second.time_range_to_in_minutes_from_start), 0);
}
}
return 0;
}
uint32_t Utilities::getFirstDurationStep(Configuration const *cfg, PaymentMethod methodId) { uint32_t Utilities::getFirstDurationStep(Configuration const *cfg, PaymentMethod methodId) {
int const popId = cfg->PaymentOption.find(methodId)->second.pop_id; int const popId = cfg->PaymentOption.find(methodId)->second.pop_id;
@ -412,10 +481,10 @@ uint32_t Utilities::getFirstDurationStep(Configuration const *cfg, PaymentMethod
} }
BusinessHours Utilities::getBusinessHours(Configuration const *cfg, PaymentMethod methodId) { BusinessHours Utilities::getBusinessHours(Configuration const *cfg, PaymentMethod methodId) {
int businessHours = cfg->PaymentOption.find(methodId)->second.pop_business_hours; uint64_t businessHours = cfg->PaymentOption.find(methodId)->second.pop_business_hours;
switch (businessHours) { switch (businessHours) {
case NoRestriction_24_7: return BusinessHours::NoRestriction_24_7; //case NoRestriction_24_7: return BusinessHours::NoRestriction_24_7;
case OnlyWorkingDays: return BusinessHours::OnlyWorkingDays; case OnlyWorkingDays: return BusinessHours::OnlyWorkingDays;
case OnlyWeekDays: return BusinessHours::OnlyWeekDays; case OnlyWeekDays: return BusinessHours::OnlyWeekDays;
case OnlyWeekEnd: return BusinessHours::OnlyWeekEnd; case OnlyWeekEnd: return BusinessHours::OnlyWeekEnd;
@ -425,6 +494,21 @@ BusinessHours Utilities::getBusinessHours(Configuration const *cfg, PaymentMetho
case SpecialAndSchoolHolidays: return BusinessHours::SpecialAndSchoolHolidays; case SpecialAndSchoolHolidays: return BusinessHours::SpecialAndSchoolHolidays;
case OnlyOpenForBusinessDays: return BusinessHours::OnlyOpenForBusinessDays; case OnlyOpenForBusinessDays: return BusinessHours::OnlyOpenForBusinessDays;
case AllDaysWithRestrictedHours: return BusinessHours::AllDaysWithRestrictedHours; case AllDaysWithRestrictedHours: return BusinessHours::AllDaysWithRestrictedHours;
case _NO_RESTRICTION_24_7_: return BusinessHours::NO_RESTRICTION_24_7;
case _MON_: return BusinessHours::MON;
case _TUE_: return BusinessHours::TUE;
case _WED_: return BusinessHours::WED;
case _THU_: return BusinessHours::THU;
case _FRI_: return BusinessHours::FRI;
case _SAT_: return BusinessHours::SAT;
case _SUN_: return BusinessHours::SUN;
case _WEEK_DAYS_: return BusinessHours::WEEK_DAYS;
case _WORKING_DAYS_: return BusinessHours::WORKING_DAYS;
case _ALL_DAYS_: return BusinessHours::ALL_DAYS;
case _OFFICIAL_HOLIDAY_: return BusinessHours::OFFICIAL_HOLIDAY;
case _ONLY_WEEKEND_: return BusinessHours::ONLY_WEEKEND;
case _ONLY_OPEN_FOR_BUSINESS_DAYS_: return BusinessHours::ONLY_OPEN_FOR_BUSINESS_DAYS;
case _NOT_DEFINED_: return BusinessHours::NOT_DEFINED;
} }
return BusinessHours::NoBusinessHoursDefined; return BusinessHours::NoBusinessHoursDefined;
} }
@ -439,3 +523,82 @@ double Utilities::computeWeekDaysDurationUnit(Configuration const *cfg, PaymentM
int durationId = cfg->PaymentRate.find(pop_id)->second.pra_payment_unit_id; int durationId = cfg->PaymentRate.find(pop_id)->second.pra_payment_unit_id;
return (double)(cfg->Duration.find(durationId)->second.pun_duration); return (double)(cfg->Duration.find(durationId)->second.pun_duration);
} }
bool Utilities::isDayIncluded(uint64_t businessHours, QDateTime const &dt) {
int dayOfWeek = dt.date().dayOfWeek();
switch (dayOfWeek) {
case Qt::Monday:
return ((businessHours & BusinessHours::MON) == BusinessHours::MON);
case Qt::Tuesday:
return ((businessHours & BusinessHours::TUE) == BusinessHours::TUE);
case Qt::Wednesday:
return ((businessHours & BusinessHours::WED) == BusinessHours::WED);
case Qt::Thursday:
return ((businessHours & BusinessHours::THU) == BusinessHours::THU);
case Qt::Friday:
return ((businessHours & BusinessHours::FRI) == BusinessHours::FRI);
case Qt::Saturday:
return ((businessHours & BusinessHours::SAT) == BusinessHours::SAT);
case Qt::Sunday:
return ((businessHours & BusinessHours::SUN) == BusinessHours::SUN);
default:;
}
return false;
}
QStringList Utilities::dumpBusinessHours(uint64_t businessHours) {
QStringList s;
if ((businessHours & BusinessHours::MON) == BusinessHours::MON) {
if ((businessHours & BusinessHours::OFFICIAL_HOLIDAY) == BusinessHours::OFFICIAL_HOLIDAY) {
s << "MON (Holiday)";
} else {
s << "MON";
}
}
if ((businessHours & BusinessHours::TUE) == BusinessHours::TUE) {
if ((businessHours & BusinessHours::OFFICIAL_HOLIDAY) == BusinessHours::OFFICIAL_HOLIDAY) {
s << "TUE (Holiday)";
} else {
s << "TUE";
}
}
if ((businessHours & BusinessHours::WED) == BusinessHours::WED) {
if ((businessHours & BusinessHours::OFFICIAL_HOLIDAY) == BusinessHours::OFFICIAL_HOLIDAY) {
s << "WED (Holiday)";
} else {
s << "WED";
}
}
if ((businessHours & BusinessHours::THU) == BusinessHours::THU) {
if ((businessHours & BusinessHours::OFFICIAL_HOLIDAY) == BusinessHours::OFFICIAL_HOLIDAY) {
s << "THU (Holiday)";
} else {
s << "THU";
}
}
if ((businessHours & BusinessHours::FRI) == BusinessHours::FRI) {
if ((businessHours & BusinessHours::OFFICIAL_HOLIDAY) == BusinessHours::OFFICIAL_HOLIDAY) {
s << "FRI (Holiday)";
} else {
s << "FRI";
}
}
if ((businessHours & BusinessHours::SAT) == BusinessHours::SAT) {
if ((businessHours & BusinessHours::OFFICIAL_HOLIDAY) == BusinessHours::OFFICIAL_HOLIDAY) {
s << "SAT (Holiday)";
} else {
s << "SAT";
}
}
if ((businessHours & BusinessHours::SUN) == BusinessHours::SUN) {
if ((businessHours & BusinessHours::OFFICIAL_HOLIDAY) == BusinessHours::OFFICIAL_HOLIDAY) {
s << "SUN (Holiday)";
} else {
s << "SUN";
}
}
return s;
}

882
main/MessageHelper.cpp Normal file

@ -0,0 +1,882 @@
#include "MessageHelper.h"
#include "terminal_utils.h"
#include "aes128.h"
#include <QDateTime>
#include <QDebug>
#define IUC_ASYNCHPOS_COINCOIDE_H 0x09
#define IUC_ASYNCHPOS_COINCOIDE_L 0x78
#define IUC_ASYNCHPOS_MAX_ARRAY_SIZE 1024
#define IUC_ASYNCHPOS_MAX_TX_PACKET_SIZE 300
#define IUC_ASYNCHPOS_MAX_RX_PACKET_SIZE 10000 // 17000
#define IUC_ASYNCHPOS_MIN_PACKET_SIZE 16
#define IUC_ASYNCHPOS_MIN_BASE_DATA_SIZE 32
#define IUC_ASYNCHPOS_MIN_BASE_BYTE_DATA_SIZE 16
#define IUC_ASYNCHPOS_POLYNOME 0xedb88320 // 0x04C11DB7
#define IUC_ASYNCHPOS_POLYNOME_INITIAL 0 // 0xFFFFFFFF
#define IUC_ASYNCHPOS_PRINTTIMOUT 1000
#define PACKET_ID_SIZE 8
#define MAX_POSID_LENGTH 255
#define STX ((char)0x01)
#define ETX1 ((char)0x02)
#define ETX2 ((char)0x03)
#define EOT ((char)0x04)
#define ENQ ((char)0x05)
#define ACK1 ((char)0x06)
#define ACK2 ((char)0x07)
#define DLE ((char)0x10)
#define NAK ((char)0x15)
#define DBG_HEADER "(" << __func__ << ":" << __LINE__ << ")"
#define DBG_EMERGENCY (0) // System is unusable
#define DBG_ALERT (1) // Action must be taken immediately
#define DBG_CRITICAL (2) // Critical conditions
#define DBG_ERROR (3) // Error conditions
#define DBG_WARNING (4) // Warning conditions
#define DBG_NOTICE (5) // Normal but significant conditions
// Conditions that are not error conditions, but that may require special handling
#define DBG_INFORMATION (6) // Informational messages
// Confirmation that the program is working as expected
#define DBG_DEBUG (7) // Debug-level messages
// Messages that contain information normally of use only when debugging a program
static int DBG_LEVEL = DBG_INFORMATION;
//static int DBG_LEVEL = DBG_DEBUG;
struct MessageHeader {
uint8_t packetType;
uint8_t packetID[PACKET_ID_SIZE];
uint8_t POSIDLength;
uint8_t POSID[MAX_POSID_LENGTH];
};
MessageHelper::AsynchBillData MessageHelper::m_asyncBillData;
MessageHelper::AuthorizationResult MessageHelper::m_authorizationResult;
MessageHelper::MessageHelper(QString const &posID, QString const &apak)
: m_posID(posID.toUtf8().constData())
, m_posIDLength(m_posID.size())
, m_messageHeaderPrefix(1 + PACKET_ID_SIZE + 1, 0x00)
, m_rawPacket(IUC_ASYNCHPOS_MAX_TX_PACKET_SIZE, 0x00) {
m_messageHeaderPrefix[9] = (uint8_t)m_posID.size();
for (int p = 0; p < apak.size(); p+=2) {
uint8_t n = strtoul(apak.mid(p, 2).toStdString().c_str(), nullptr, 16);
m_apak.push_back(n);
}
if (DBG_LEVEL >= DBG_DEBUG) {
qCritical() << DBG_HEADER << apak << m_apak.toHex(':');
qCritical() << DBG_HEADER << m_posID.toHex(':');
qCritical() << DBG_HEADER << m_messageHeaderPrefix.toHex(':');
}
}
MessageHelper::MessageHelper(QByteArray const &posID, QString const &apak)
: m_posID(posID)
, m_posIDLength(m_posID.size())
, m_messageHeaderPrefix(1 + PACKET_ID_SIZE + 1, 0x00)
, m_rawPacket(IUC_ASYNCHPOS_MAX_TX_PACKET_SIZE, 0x00) {
m_messageHeaderPrefix[9] = (uint8_t)m_posID.size();
for (int p = 0; p < apak.size(); p+=2) {
uint8_t n = strtoul(apak.mid(p, 2).toStdString().c_str(), nullptr, 16);
m_apak.push_back(n);
}
if (DBG_LEVEL >= DBG_DEBUG) {
qCritical() << DBG_HEADER << apak << m_apak.toHex(':');
qCritical() << DBG_HEADER << m_posID.toHex(':');
qCritical() << DBG_HEADER << m_messageHeaderPrefix.toHex(':');
}
}
MessageHelper::~MessageHelper() {
}
void MessageHelper::handleMessage(char const *pData) {
#if 0
//unsigned char marker = pData[0];
// unsigned int tagNameLength = pData[1];
unsigned char tagName[IUC_ASYNCHPOS_MIN_BASE_DATA_SIZE];
// unsigned int curElementLength = 0;
//unsigned char curElement[IUC_ASYNCHPOS_MIN_BASE_DATA_SIZE];
//unsigned char receiptData[IUC_ASYNCHPOS_MAX_ARRAY_SIZE + 1];
unsigned char rxBuf[20];
// unsigned char flags[129];
// unsigned char docNr[32];
//unsigned char messageType = pData[1];
unsigned int uitmp = 0;
unsigned int uitmp2 = 0;
iuc_asynchpos_sub_initArray(tagName, IUC_ASYNCHPOS_MIN_BASE_DATA_SIZE);
//iuc_asynchpos_sub_initArray(curElement, IUC_ASYNCHPOS_MIN_BASE_DATA_SIZE);
uitmp = biox_FindStrInBufferInt("LoginResult",pData) | biox_FindStrInBuffer("LOGINRESULT",pData);
if (uitmp) {
asynchState = 0x02; //eingeloggt
/*rxBuf[0] = 0x45;
rxBuf[1] = 0x00;
rxBuf[2] = 0x00;
vmc_SendWithBuffer(rxBuf,40,0x69,0);*/
}
uitmp = biox_FindStrInBufferInt("AuthorizationStarted",pData) | biox_FindStrInBuffer("AUTHORIZATIONSTARTED",pData);
if (uitmp) {
iuc_asynchpos_sub_initArray(rxBuf,5);
rxBuf[0] = 0x53;
rxBuf[1] = 0x00;
rxBuf[2] = 0x00;
vmc_SendWithBuffer(rxBuf,5,0x69,0);
}
uitmp = biox_FindStrInBufferInt("AuthorizationResult",pData) | biox_FindStrInBuffer("AUTHORIZATIONRESULT",pData);
if (uitmp) {
asynchState = 0x03; //successfully authorized
iuc_asynchpos_sub_clear_message(0x00);
uitmp = biox_FindStrInBufferInt("ID",pData);
biox_CopyBlock(pData, uitmp + 2, asynchBill.id, 0, pData[uitmp + 1]);
uitmp = biox_FindStrInBufferInt("DocNr",pData) | biox_FindStrInBuffer("DOCNR",pData);
biox_CopyBlock(pData, uitmp + 2, asynchBill.docNr, 0, pData[uitmp + 1]);
//uitmp = biox_FindStrInBuffer("Result",pData) | biox_FindStrInBuffer("RESULT",pData);
//biox_CopyBlock(pData, uitmp + 2, asynchBill.result, 0, pData[uitmp + 1]);
brd_SendDiagStr("->IUC ASYNCHPOS message ID: ",0);
brd_SendDiagBlock(asynchBill.id,1,36);
/*if (iuc_asynch_PrintControl) {
brd_SendDiagStr("->IUC ASYNCHPOS print data send AUTH: ",1);
vmc_SendWithBuffer(receiptData,IUC_ASYNCHPOS_MAX_ARRAY_SIZE,0x69,0);
iuc_asynch_PrintControl = 0x00;
//biox_delay_ms(750);
} else {
brd_SendDiagStr("->IUC ASYNCHPOS sending authorization: ",1);
iuc_asynch_PrintControl = 0x01;
}*/
uitmp = biox_FindStrInBufferInt("ERROR",pData);
if (!uitmp/*biox_FindStrInBuffer("OK",pData) | biox_FindStrInBuffer("Approved",pData) | biox_FindStrInBuffer("APPROVED",asynchBill.result)*/) {
iuc_asynch_PrintControl |= 0xF0;
/*uitmp = biox_FindStrInBufferInt("Amount",pData) | biox_FindStrInBufferInt("AMOUNT",pData);
//if (pData[uitmp + 1] <= 10) {
biox_CopyBlock(pData, uitmp + 2, asynchBill.amount, 0, pData[uitmp + 1]);
//} else {
//biox_CopyBlock(pData, uitmp + 2, asynchBill.amount, 0, 10);
//}*/
//uitmp = biox_FindStrInBuffer("Token",pData);
//biox_CopyBlock(pData, uitmp + 2, asynchBill.token, 0, pData[uitmp + 1]);
/*uitmp = biox_FindStrInBufferInt("Authcode",pData) | biox_FindStrInBufferInt("AUTHCODE",pData);
biox_CopyBlock(pData, uitmp + 2, asynchBill.authCode, 0, pData[uitmp + 1]);
uitmp = biox_FindStrInBufferInt("RRN",pData);
biox_CopyBlock(pData, uitmp + 2, asynchBill.rrn, 0, pData[uitmp + 1]);
uitmp = biox_FindStrInBufferInt("STAN",pData);
biox_CopyBlock(pData, uitmp + 2, asynchBill.stan, 0, pData[uitmp + 1]);
uitmp = biox_FindStrInBufferInt("CardType",pData) | biox_FindStrInBufferInt("CARDTYPE",pData);
biox_CopyBlock(pData, uitmp + 2, asynchBill.cardtype, 0, pData[uitmp + 1]);*/
asynchState = 0x04;
brd_SendDiagStr("->IUC ASYNCHPOS authorization confirmed.",1);
/*iuc_asynchpos_sub_initArray(rxBuf,20);
rxBuf[0] = 0x45;
rxBuf[1] = 0x00;
rxBuf[2] = 0x00;
vmc_SendWithBuffer(rxBuf,20,0x69,0);*/
//iuc_asynchpos_resetBuffers(0x01);
//iuc_asynchpos_command_close_Document();
} else {
iuc_asynch_PrintControl |= 0xF0;
//uitmp = biox_FindStrInBufferInt("ErrCode",pData) | biox_FindStrInBufferInt("ERRCODE",pData);
//biox_CopyBlock(pData, uitmp + 2, asynchBill.errCode, 0, pData[uitmp + 1]);
brd_SendDiagStr("->IUC ASYNCHPOS authorization failed.",1);
/*iuc_asynchpos_sub_initArray(rxBuf,20);
rxBuf[0] = 0x45;
rxBuf[1] = 0xFF;
biox_CopyBlock(pData, uitmp + 2, rxBuf, 2, pData[uitmp + 1]);
vmc_SendWithBuffer(rxBuf,20,0x69,0);*/
iuc_asynch_keepAlive = 0x00;
//VendRequest=0;
}
}
uitmp = biox_FindStrInBufferInt("PrintReceipt",pData) | biox_FindStrInBufferInt("PRINTRECEIPT",pData);
if (uitmp) {
asynchState = 0x03; //Customer receipt recieved
//iuc_asynchpos_sub_initArray(flags,129);
//uitmp = biox_FindStrInBufferInt("Flag",pData) | biox_FindStrInBufferInt("FLAG",pData) | biox_FindStrInBufferInt("Flags",pData) | biox_FindStrInBufferInt("FLAGS",pData);
/*if (uitmp) {
biox_CopyBlock(pData, uitmp + 2, flags, 0, pData[uitmp + 1]);
uitmp = biox_FindStrInBufferInt("CD",flags) | biox_FindStrInBufferInt("LR",flags);
}*/
/*iuc_asynchpos_sub_clear_message(0x00);
uitmp = biox_FindStrInBufferInt("ID",pData);
biox_CopyBlock(pData, uitmp + 2, asynchBill.id, 0, pData[uitmp + 1]);
uitmp = biox_FindStrInBufferInt("DocNr",pData) | biox_FindStrInBuffer("DOCNR",pData);
biox_CopyBlock(pData, uitmp + 2, asynchBill.docNr, 0, pData[uitmp + 1]);*/
iuc_asynchpos_sub_initArray(asynchBill.printId,129);
uitmp = biox_FindStrInBufferInt("ID",pData);
biox_CopyBlock(pData, uitmp + 2, asynchBill.printId, 0, pData[uitmp + 1]);
//if(asynchState == 0x02/* && uitmp biox_FindStrInBufferInt("CD",flags) || biox_FindStrInBufferInt("LR",flags)*/) {
if((!iuc_asynch_PRNrecieved) && (biox_FindStrInBufferInt("CD",pData) || biox_FindStrInBufferInt("LR",pData)) ) {
iuc_asynch_PRNrecieved = 0x01;
iuc_asynchpos_sub_initArray(receiptData,IUC_ASYNCHPOS_MAX_ARRAY_SIZE + 1);
uitmp = /*biox_FindStrInBuffer("ReceiptText",pData) | */biox_FindStrInBufferInt("RECEIPTTEXT",pData);
uitmp2 = (pData[uitmp] * 256) + pData[uitmp + 1];
//if (uitmp2 <= IUC_ASYNCHPOS_MAX_ARRAY_SIZE) {
if (uitmp2 > IUC_ASYNCHPOS_MAX_ARRAY_SIZE) {
uitmp2 = IUC_ASYNCHPOS_MAX_ARRAY_SIZE;
brd_SendDiagStr("->IUC ASYNCHPOS receipt: ERROR. Receipt too large! Cutting off.",1);
/*receiptData[0] = 0x50;
biox_CopyBlock(pData, uitmp + 2, receiptData, 1, uitmp2/*IUC_ASYNCHPOS_MAX_ARRAY_SIZE*);
//uitmp += IUC_ASYNCHPOS_MAX_ARRAY_SIZE;
//uitmp2 -= IUC_ASYNCHPOS_MAX_ARRAY_SIZE;
brd_SendDiagStr("->IUC ASYNCHPOS receipt: ",0);
brd_SendDiagBlock(receiptData,1,IUC_ASYNCHPOS_MAX_ARRAY_SIZE);
iuc_asynch_PrintControl |= 0x0F;*/
/*if (iuc_asynch_PrintControl) {
brd_SendDiagStr("->IUC ASYNCHPOS print data send: ",1);
vmc_SendWithBuffer(receiptData,IUC_ASYNCHPOS_MAX_ARRAY_SIZE,0x69,0);
iuc_asynch_PrintControl = 0x00;
} else {
brd_SendDiagStr("->IUC ASYNCHPOS print data stored: ",1);
iuc_asynch_PrintControl = 0x01;
}*/
//biox_delay_ms(750);
//iuc_asynchpos_resetBuffers(0x01);
//iuc_asynchpos_command_close_Document();
//iuc_asynchpos_resetBuffers(0x02);
//iuc_asynchpos_command_print_Result(0x01);
}
receiptData[0] = 0x50;
biox_CopyBlock(pData, uitmp + 2, receiptData, 1, uitmp2/*IUC_ASYNCHPOS_MAX_ARRAY_SIZE*/);
brd_SendDiagStr("->IUC ASYNCHPOS receipt: ",0);
brd_SendDiagBlock(receiptData,1,IUC_ASYNCHPOS_MAX_ARRAY_SIZE);
iuc_asynch_PrintControl |= 0x0F;
/* else {
//receiptData[0] = 0x50;
//iuc_asynchpos_sub_initZero(receiptData,1);
brd_SendDiagStr("->IUC ASYNCHPOS receipt: ERROR. Receipt too large!",1);
iuc_asynch_PrintControl |= 0x0E;
} */
/* else {
//iuc_asynchpos_resetBuffers(0x02);
iuc_asynchpos_command_print_Result(0x00);
}*/
}
//++iuc_print_counter;
//if(asynchState == 0x04 && iuc_asynch_PrintControl == 0) {
//iuc_asynchpos_resetBuffers(0x01);
//iuc_asynchpos_resetBuffers(0x00);
//iuc_asynchpos_command_print_Result(0x01);
/*} /else {
//iuc_asynchpos_resetBuffers(0x02);
iuc_asynchpos_command_print_Result(0x01);
}*/
//iuc_asynchpos_command_print_Result(0x01);
/*while (uitmp2 > IUC_ASYNCHPOS_MAX_ARRAY_SIZE) {
biox_CopyBlock(pData, uitmp + 2, receiptData, 0, IUC_ASYNCHPOS_MAX_ARRAY_SIZE);
uitmp += IUC_ASYNCHPOS_MAX_ARRAY_SIZE;
uitmp2 -= IUC_ASYNCHPOS_MAX_ARRAY_SIZE;
vmc_SendWithBuffer(receiptData,IUC_ASYNCHPOS_MAX_ARRAY_SIZE,0x69,0);
}
//Rest des Packets
biox_CopyBlock(pData, uitmp + 2, receiptData, 0, uitmp2);
vmc_SendWithBuffer(receiptData,uitmp2,0x69,0);
//iuc_asynchpos_resetBuffers(0x02);
iuc_asynchpos_command_print_Result(0x01);*/
}
uitmp = biox_FindStrInBufferInt("VoidResult",pData) | biox_FindStrInBufferInt("VOIDRESULT",pData);
if (uitmp) {
asynchState = 0x01; //There was a cancel. Relogin and try again.
uitmp = biox_FindStrInBufferInt("ERROR",pData);
if (uitmp) {
rxBuf[0] = 0x45;
rxBuf[1] = 0x56;
rxBuf[2] = 0x45;
vmc_SendWithBuffer(rxBuf,3,0x69,0);
}
uitmp = biox_FindStrInBufferInt("REFUND",pData);
if (uitmp) {
rxBuf[0] = 0x45;
rxBuf[1] = 0x56;
rxBuf[2] = 0x52;
vmc_SendWithBuffer(rxBuf,3,0x69,0);
//TODO refund bill here. Should not trigger, but it might.
}
}
uitmp = biox_FindStrInBufferInt("DocClosed",pData);
if (uitmp) {
asynchState = 0x01; //Transaction successful
//if (VendRequest)
GWstate.VendRequest=0;
}
#endif
}
void MessageHelper::handleCommand(AsyncPosCommand command, char status) {
//r - registration, a - authorization, c - cancel, s - storno, k - kassenschnitt
#if 0
UCHAR tempBuf[3];
UCHAR rxBuf[8];
// UINT uitemp = 0;
UINT uitmp= 700;
tempBuf[0] = 0x00;
tempBuf[1] = 0x00;
tempBuf[2] = 0x00;
timeHoldISMAS = GWglobTime.SecOfDay;
iuc_asynchpos_sub_initArray(rxBuf,8);
//iuc_asynchpos_resetBuffers(0x00);
switch (command) {
case 0x72: //registration
//iuc_asynchpos_init();
asynchState = 0x01;
iuc_asynchpos_command_Login();
GWstate.VendRequest=1;
break;
case 0x61: //authorisation
iuc_asynch_keepAlive = 0x01;
iuc_asynch_PrintControl = 0;
iuc_asynchpos_sub_clear_message(0x01);
//VendRequest=1;
iuc_asynchpos_resetBuffers(0x00);
///#ifdef IUC_ASYCHNPOS_TESTMODE
//iuc_asynchpos_command_authorize(uitmp);
//#else
iuc_asynchpos_command_authorize(Vend.Amount);
//#endif
break;
case 0x63: //cancel
case 0x73: //storno
/*if (asynchState <= 0x02 != 0) { //Authorization result recieved?
iuc_asynchpos_command_cancel_authorize();
} else {*/
iuc_asynchpos_command_close_Document(0x01);
//}
iuc_asynch_keepAlive = 0x00;
//VendRequest=0;
break;
case 0x6B: //kassenschnitt
iuc_asynchpos_command_Logout();
break;
case 0x62: //get last bill
//iuc_zvt_getLastBill(tempBuf);
break;
case 0x01: iuc_asynchpos_command_close_Document(0x00);
iuc_asynch_keepAlive = 0x00;
//VendRequest=0;
break;
case 0x70: iuc_asynchpos_command_ping_terminal();
break;
default:
break;
}
#endif
}
void MessageHelper::createRawPacket(PacketType packetType,
QByteArray const &encryptedPacketID,
QByteArray const &message) {
if (createMessageHeaderPrefix(packetType, encryptedPacketID)) {
QByteArray ba(m_messageHeaderPrefix);
ba = ba.append(m_posID);
ba = ba.append(message);
uint16_t const size = ba.size();
ba.push_front((char)size);
ba.push_front((char)(size >> 8));
m_rawPacket = ba;
}
}
bool MessageHelper::setMessageHeaderPacketType(PacketType packetType) {
switch (packetType) {
case PacketType::POS_ECR:
case PacketType::MESSAGE_RECEIVED_POSITIVE_ACK:
case PacketType::MESSAGE_RECEIVED_NEGATIVE_ACK:
m_messageHeaderPrefix[0] = (uint8_t)packetType;
break;
default:
return false;
}
return true;
}
bool MessageHelper::createMessageHeaderPrefix(PacketType packetType, QByteArray const &encryptedPacketID) {
if (encryptedPacketID.size() == PACKET_ID_SIZE) {
if (setMessageHeaderPacketType(packetType)) {
for (int i = 1; i <= 8; ++i) {
m_messageHeaderPrefix[i] = (uint8_t)encryptedPacketID[i-1];
}
if (DBG_LEVEL >= DBG_DEBUG) {
qCritical() << DBG_HEADER << m_messageHeaderPrefix.toHex(':');
}
return true;
}
}
return false;
}
QByteArray const &MessageHelper::generateUniqueTransactionID(QString const &machineNr,
QString const &customerNr) {
// TODO: wieder entfernen
QDateTime dt(QDateTime::fromString("2024-06-18T12:00:00", Qt::ISODate));
uint64_t const transID = MessageHelper::secsSinceJan2017(dt);
m_uniqueTransactionID.clear();
m_uniqueTransactionID = m_uniqueTransactionID.append(QByteArray(std::to_string(transID).c_str(), 9).rightJustified(10, '0'));
m_uniqueTransactionID = m_uniqueTransactionID.append(QByteArray(machineNr.toStdString().c_str()).rightJustified(5, '0'));
m_uniqueTransactionID = m_uniqueTransactionID.append(QByteArray(customerNr.toStdString().c_str()).rightJustified(4, '0'));
return m_uniqueTransactionID;
}
// actual payment. amount to pay is known.
void MessageHelper::createAuthorizeMessage() {
m_authorizeMessage.clear();
m_authorizeMessage.push_back((char)0x89); // 9 in 0x89 is the size
m_authorizeMessage = m_authorizeMessage.append(QByteArray("Authorize"));
QString const &price= m_price.setNum(1000);
m_authorizeMessage.push_back((char)0x06);
m_authorizeMessage = m_authorizeMessage.append(QByteArray("Amount"));
m_authorizeMessage.push_back((char)0x00);
m_authorizeMessage.push_back((char)price.size());
m_authorizeMessage = m_authorizeMessage.append(QByteArray(price.toStdString().c_str()));
m_authorizeMessage.push_back((char)0x04);
m_authorizeMessage = m_authorizeMessage.append(QByteArray("Cash"));
m_authorizeMessage.push_back((char)0x00);
m_authorizeMessage.push_back((char)0x01);
m_authorizeMessage.push_back((char)0x30);
m_authorizeMessage.push_back((char)0x08);
m_authorizeMessage = m_authorizeMessage.append(QByteArray("Currency"));
m_authorizeMessage.push_back((char)0x00);
m_authorizeMessage.push_back((char)0x03);
m_authorizeMessage = m_authorizeMessage.append(QByteArray("978"));
m_authorizeMessage.push_back((char)0x05);
m_authorizeMessage = m_authorizeMessage.append(QByteArray("DocNr"));
m_authorizeMessage.push_back((char)0x00);
m_authorizeMessage.push_back((char)0x13);
m_authorizeMessage = m_authorizeMessage.append(generateUniqueTransactionID("1000", "100"));
m_authorizeMessage.push_back((char)0x04);
m_authorizeMessage = m_authorizeMessage.append(QByteArray("Time"));
m_authorizeMessage.push_back((char)0x00);
m_authorizeMessage.push_back((char)0x13);
QDateTime current = QDateTime::currentDateTime();
// TODO: wieder entfernen
current.setTime(QTime(12, 0, 0));
current.setDate(QDate(2024, 6, 18));
QByteArray time(current.toString(Qt::ISODate).toStdString().c_str());
time[10] = ' ';
m_authorizeMessage = m_authorizeMessage.append(QByteArray(time));
m_authorizeMessage.push_back((char)0x04);
m_authorizeMessage = m_authorizeMessage.append(QByteArray("Lang"));
m_authorizeMessage.push_back((char)0x00);
m_authorizeMessage.push_back((char)0x02);
m_authorizeMessage = m_authorizeMessage.append(QByteArray("lt"));
m_authorizeMessage.push_back((char)0x00);
}
void MessageHelper::createCancelAuthorizeMessage() {
m_cancelAuthorizeMessage.clear();
m_cancelAuthorizeMessage.push_back((char)0x96); // 0x80 + 0x16
m_cancelAuthorizeMessage = m_cancelAuthorizeMessage.append(QByteArray("AuthorizationCancelled"));
m_cancelAuthorizeMessage.push_back((char)0x02);
m_cancelAuthorizeMessage = m_authorizeMessage.append(QByteArray("ID"));
m_cancelAuthorizeMessage.push_back((char)0x00);
m_cancelAuthorizeMessage.push_back((char)QByteArray(m_asyncBillData.id).size());
m_cancelAuthorizeMessage = m_cancelAuthorizeMessage.append(QByteArray(m_asyncBillData.id));
m_cancelAuthorizeMessage.push_back((char)0x00);
}
void MessageHelper::createPingMessage() {
m_pingMessage.clear();
m_pingMessage.push_back((char)0x84); // 4 in 0x84 is the size
m_pingMessage = m_pingMessage.append(QByteArray("Ping"));
m_pingMessage.push_back((char)0x04);
m_pingMessage = m_authorizeMessage.append(QByteArray("Time"));
m_pingMessage.push_back((char)0x00);
m_pingMessage.push_back((char)0x13);
QDateTime current = QDateTime::currentDateTime();
// TODO: wieder entfernen
current.setTime(QTime(12, 0, 0));
current.setDate(QDate(2024, 6, 18));
QByteArray time(current.toString(Qt::ISODate).toStdString().c_str());
time[10] = ' ';
m_pingMessage = m_pingMessage.append(QByteArray(time));
m_pingMessage.push_back((char)0x00);
}
void MessageHelper::createCloseDocumentMessage(bool storno) {
m_closeDocumentMessage.clear();
m_closeDocumentMessage.push_back((char)0x89); // 9 in 0x89 is the size
m_closeDocumentMessage = m_closeDocumentMessage.append(QByteArray("DocClosed"));
m_closeDocumentMessage.push_back((char)0x05);
m_closeDocumentMessage = m_closeDocumentMessage.append(QByteArray("DocNr"));
uint16_t const docNrSize = m_uniqueTransactionID.size();
m_closeDocumentMessage.push_back((char)(docNrSize >> 8));
m_closeDocumentMessage.push_back((char)(docNrSize));
m_closeDocumentMessage = m_closeDocumentMessage.append(m_uniqueTransactionID);
if (!storno) {
m_closeDocumentMessage.push_back((char)0x06);
m_closeDocumentMessage = m_closeDocumentMessage.append(QByteArray("AuthID"));
QByteArray ba(m_authorizationResult.m_id.toStdString().c_str());
uint16_t const authIdSize = ba.size();
m_closeDocumentMessage.push_back((char)(authIdSize >> 8));
m_closeDocumentMessage.push_back((char)(authIdSize));
m_closeDocumentMessage = m_closeDocumentMessage.append(ba);
}
m_closeDocumentMessage.push_back((char)0x00);
}
void MessageHelper::createPrintResultMessage() {
m_printResultMessage.clear();
}
uint32_t MessageHelper::secsSinceJan2017(QDateTime const &dt) {
return QDateTime(QDateTime::fromString("2017-01-01T00:00:00", Qt::ISODate)).secsTo(dt);
}
void MessageHelper::createLoginMessage() {
m_loginMessage.clear();
m_loginMessage.push_back((char)0x85); // 5 in 0x85 is the size
m_loginMessage = m_loginMessage.append(QByteArray("Login"));
m_loginMessage.push_back((char)0x04);
m_loginMessage = m_loginMessage.append(QByteArray("Time"));
m_loginMessage.push_back((char)0x00);
m_loginMessage.push_back((char)0x13);
QDateTime current = QDateTime::currentDateTime();
// TODO: wieder entfernen
current.setTime(QTime(12, 0, 0));
current.setDate(QDate(2024, 6, 18));
QByteArray time(current.toString(Qt::ISODate).toStdString().c_str());
time[10] = ' ';
m_loginMessage = m_loginMessage.append(time);
m_loginMessage.push_back((char)0x05);
m_loginMessage = m_loginMessage.append(QByteArray("Flags"));
m_loginMessage.push_back((char)0x00);
m_loginMessage.push_back((char)0x06);
m_loginMessage = m_loginMessage.append(QByteArray("AP3|LR"));
m_loginMessage.push_back((char)0x00);
if (DBG_LEVEL >= DBG_INFORMATION) {
qCritical() << DBG_HEADER << "loginMessage" << m_loginMessage.toHex(':');
}
}
void MessageHelper::createLogoutMessage() {
m_logoutMessage.clear();
m_logoutMessage.push_back((char)0x86); // 6 in 0x86 is the size
m_logoutMessage = m_loginMessage.append(QByteArray("Logout"));
m_loginMessage.push_back((char)0x04);
m_loginMessage = m_loginMessage.append(QByteArray("Time"));
m_loginMessage.push_back((char)0x00);
m_loginMessage.push_back((char)0x13);
QDateTime current = QDateTime::currentDateTime();
// TODO: wieder entfernen
current.setTime(QTime(12, 0, 0));
current.setDate(QDate(2024, 6, 18));
QByteArray time(current.toString(Qt::ISODate).toStdString().c_str());
time[10] = ' ';
m_logoutMessage = m_logoutMessage.append(time);
m_loginMessage.push_back((char)0x00);
if (DBG_LEVEL >= DBG_INFORMATION) {
qCritical() << DBG_HEADER << "loginMessage" << m_logoutMessage.toHex(':');
}
}
QByteArrayList const &MessageHelper::createMessageChunksToSend(AsyncPosCommand cmd, char etx) {
QByteArray encryptedPacketID(QByteArray("\x01\x02\x03\x04\x05\x06\x07\x08"));
m_messageChunkList.clear();
switch (cmd) {
case (int)MessageHelper::AsyncPosCommand::LOGIN:
createLoginMessage();
createRawPacket(PacketType::POS_ECR, encryptedPacketID, m_loginMessage);
break;
case (int)MessageHelper::AsyncPosCommand::LOGOUT:
createLogoutMessage();
createRawPacket(PacketType::POS_ECR, encryptedPacketID, m_logoutMessage);
break;
case (int)MessageHelper::AsyncPosCommand::AUTHORIZE:
createAuthorizeMessage();
createRawPacket(PacketType::POS_ECR, encryptedPacketID, m_authorizeMessage);
break;
case (int)MessageHelper::AsyncPosCommand::CLOSE_DOCUMENT:
createCloseDocumentMessage(); // actung: hier default parameter
createRawPacket(PacketType::POS_ECR, encryptedPacketID, m_closeDocumentMessage);
break;
default:;
}
if (DBG_LEVEL >= DBG_DEBUG) {
qCritical() << DBG_HEADER << m_rawPacket.toHex(':');
}
QByteArray const &ba = m_rawPacket.mid(11);
if (DBG_LEVEL >= DBG_DEBUG) {
qCritical() << DBG_HEADER << ba.toHex(':');
}
// calculate crc32 on message starting from (including) POSID length
uint32_t crc = TU::crc32(ba);
if (DBG_LEVEL >= DBG_DEBUG) {
qCritical() << DBG_HEADER << "crc32" << hex << crc;
}
unsigned char cipherText[256];
memset(cipherText, 0, sizeof(cipherText));
// XOR crc32-value (4 bytes) with APAK starting from left
// (rest of APAK untouched)
QByteArray clearText(m_apak);
clearText[0] = clearText[0] ^ ((uint8_t)(crc >> 24));
clearText[1] = clearText[1] ^ ((uint8_t)(crc >> 16));
clearText[2] = clearText[2] ^ ((uint8_t)(crc >> 8));
clearText[3] = clearText[3] ^ ((uint8_t)(crc >> 0));
if (DBG_LEVEL >= DBG_DEBUG) {
qCritical() << DBG_HEADER << "clearText" << clearText.toHex();
}
// encrypt XOR result with APAK using AES129, ECB mode
aes_encrypt((uint8_t *)clearText.data(),
(uint8_t *)cipherText,
(uint8_t *)m_apak.toStdString().c_str());
// 8 left bytes of encryption result is signature (Packet ID)
encryptedPacketID = QByteArray((const char *)cipherText, 8);
if (DBG_LEVEL >= DBG_INFORMATION) {
qCritical() << DBG_HEADER << "cipherText (new PacketID)" << encryptedPacketID.toHex(':');
}
// insert PacketID in packet
if (insertEncryptedPacketID(encryptedPacketID)) {
// build chunks to be sent over serial line
int const chunks = m_rawPacket.size() / IUC_ASYNCHPOS_MIN_PACKET_SIZE;
if (DBG_LEVEL >= DBG_DEBUG) {
qCritical() << DBG_HEADER << "nr of chunks" << chunks;
}
int i = 0;
for (; i < chunks; ++i) {
QByteArray messageChunk = m_rawPacket.mid(IUC_ASYNCHPOS_MIN_PACKET_SIZE*i,
IUC_ASYNCHPOS_MIN_PACKET_SIZE);
if (DBG_LEVEL >= DBG_DEBUG) {
qCritical() << DBG_HEADER << i << "unmasked" << messageChunk.toHex(':');
}
messageChunk = MessageHelper::mask(messageChunk);
if (DBG_LEVEL >= DBG_DEBUG) {
qCritical() << DBG_HEADER << i << " masked" << messageChunk.toHex(':');
}
messageChunk.push_back(etx == ACK1 ? ETX2 : ETX1); // etx must be ACK1 or ACK2
char const lrc = TU::lrc(messageChunk);
messageChunk.push_back(lrc);
messageChunk.push_front(STX);
if (DBG_LEVEL >= DBG_INFORMATION) {
qCritical() << DBG_HEADER << "chunk to send" << messageChunk.toHex(':');
}
m_messageChunkList += messageChunk;
}
int const rest = m_rawPacket.size() % IUC_ASYNCHPOS_MIN_PACKET_SIZE;
if (rest) {
QByteArray messageChunk = m_rawPacket.mid(IUC_ASYNCHPOS_MIN_PACKET_SIZE*chunks, rest);
if (DBG_LEVEL >= DBG_DEBUG) {
qCritical() << DBG_HEADER << i << "unmasked" << messageChunk.toHex(':');
}
messageChunk = mask(messageChunk);
if (DBG_LEVEL >= DBG_DEBUG) {
qCritical() << DBG_HEADER << i << " masked" << messageChunk.toHex(':');
}
messageChunk.push_back(etx == ACK1 ? ETX2 : ETX1); // etx must be ACK1 or ACK2
char const lrc = TU::lrc(messageChunk);
messageChunk.push_back(lrc);
messageChunk.push_front(STX);
if (DBG_LEVEL >= DBG_INFORMATION) {
qCritical() << DBG_HEADER << "chunk to send" << messageChunk.toHex(':');
}
m_messageChunkList += messageChunk;
}
}
return m_messageChunkList;
}
QByteArrayList MessageHelper::createLoginMessageChunksToSend(char etx) {
return createMessageChunksToSend(AsyncPosCommand::LOGIN, etx);
}
QByteArrayList MessageHelper::createLogoutMessageChunksToSend(char etx) {
return createMessageChunksToSend(AsyncPosCommand::LOGOUT, etx);
}
QByteArrayList MessageHelper::createAuthorizeMessageChunksToSend(char etx) {
return createMessageChunksToSend(AsyncPosCommand::AUTHORIZE, etx);
}
QByteArrayList MessageHelper::createCloseDocumentMessageChunksToSend(char etx) {
return createMessageChunksToSend(AsyncPosCommand::CLOSE_DOCUMENT, etx);
}
bool MessageHelper::insertEncryptedPacketID(QByteArray const &encryptedPacketID) {
if (encryptedPacketID.size() == PACKET_ID_SIZE) {
// m_rawPacket has already full length
for (int i = 0; i < PACKET_ID_SIZE; ++i) {
m_messageHeaderPrefix[i+1] = encryptedPacketID[i];
m_rawPacket[i+3] = encryptedPacketID[i];
}
if (DBG_LEVEL >= DBG_DEBUG) {
qCritical() << DBG_HEADER << m_messageHeaderPrefix.toHex(':');
qCritical() << DBG_HEADER << m_rawPacket.toHex(':');
}
return true;
}
return false;
}
QByteArray const &MessageHelper::mask(QByteArray &messageChunk) {
QByteArray ba;
for (int i = 0; i < messageChunk.size(); ++i) {
char const c = messageChunk[i];
switch(c) {
case STX: __attribute__((fallthrough));
case ETX1: __attribute__((fallthrough));
case ETX2: __attribute__((fallthrough));
case EOT: __attribute__((fallthrough));
case ENQ: __attribute__((fallthrough));
case ACK1: __attribute__((fallthrough));
case ACK2: __attribute__((fallthrough));
case DLE: __attribute__((fallthrough));
case NAK:
ba.push_back(char(DLE));
ba.push_back(c + 0x30);
break;
default:
ba.push_back(c);
}
}
messageChunk = ba;
return messageChunk;
}
QByteArray const &MessageHelper::unMask(QByteArray &messageChunk) {
QByteArray ba;
for (int i = 0; i < messageChunk.size(); ++i) {
char c = messageChunk[i];
if (c == (char)0x10) /* DEL */ {
if ((i+1) < messageChunk.size()) {
c = messageChunk[i+1] - (char)0x30;
}
}
ba.push_back(c);
}
messageChunk = ba;
return messageChunk;
}

112
main/MessageHelper.h Normal file

@ -0,0 +1,112 @@
#ifndef MESSAGE_HELPER_H_INCLUDED
#define MESSAGE_HELPER_H_INCLUDED
#include <cinttypes>
#include <QByteArray>
#include <QByteArrayList>
#include <QString>
#include <QDateTime>
class MessageHelper {
public:
enum PacketType : std::uint8_t {
POS_ECR = 0,
// POS_EXT = 1,
MESSAGE_RECEIVED_POSITIVE_ACK = 0x0A,
MESSAGE_RECEIVED_NEGATIVE_ACK = 0x0F
// POS_HOST_FORMAT_1_ENCRYPTED = 0x11,
// POS_HOST_FORMAT_1_UNENCRYPTED = 0x21
};
enum AsyncPosCommand : std::uint8_t {
LOGIN = 0,
LOGOUT = 1,
AUTHORIZE = 2,
CLOSE_DOCUMENT = 3
};
explicit MessageHelper(QString const &posID = "T-TPS-SELF2002in",
QString const &apak = "8AC304380E0E476BA2558B75DB9E2516");
explicit MessageHelper(QByteArray const &posID, QString const &apak);
~MessageHelper();
void createRawPacket(PacketType PacketType,
QByteArray const &encryptedPacketId,
QByteArray const &message);
bool insertEncryptedPacketID(QByteArray const &encryptedPacketID);
QByteArrayList createLoginMessageChunksToSend(char etx);
QByteArrayList createLogoutMessageChunksToSend(char etx);
QByteArrayList createAuthorizeMessageChunksToSend(char etx);
QByteArrayList createCloseDocumentMessageChunksToSend(char etx);
QByteArrayList const &createMessageChunksToSend(AsyncPosCommand cmd, char etx);
// private:
QByteArray m_posID;
QByteArray m_apak;
uint8_t m_posIDLength;
QByteArray m_messageHeaderPrefix;
QByteArray m_rawPacket; // without leading STX and trailing [ETX(1/2), LRC]
QByteArray m_loginMessage;
QByteArray m_logoutMessage;
QByteArray m_authorizeMessage;
QByteArray m_cancelAuthorizeMessage;
QByteArray m_pingMessage;
QByteArray m_printResultMessage;
QByteArray m_closeDocumentMessage;
QByteArray m_uniqueTransactionID;
QString m_price;
QByteArrayList m_messageChunkList;
bool setMessageHeaderPacketType(PacketType packetType);
bool createMessageHeaderPrefix(PacketType packetType, QByteArray const &encryptedPacketID);
void createLoginMessage();
void createLogoutMessage();
void createAuthorizeMessage();
void createCancelAuthorizeMessage();
void createPingMessage();
void createCloseDocumentMessage(bool storno = false);
void createPrintResultMessage();
void handleCommand(AsyncPosCommand command, char status);
//r - registration, a - authorization, c - cancel, s - storno, k - kassenschnitt
void handleMessage(char const *pData);
QByteArray const &generateUniqueTransactionID(QString const &machineNr, QString const &customerNumer);
static QByteArray const &mask(QByteArray &messageChunk);
static QByteArray const &unMask(QByteArray &messageChunk);
static uint32_t secsSinceJan2017(QDateTime const &dt = QDateTime::currentDateTime());
struct AsynchBillData {
char time[20];
char id[37];
char printId[129];
char docNr[33];
//unsigned char amount[10];
//unsigned char token[25];
//unsigned char result[8];
//unsigned char authCode[7];
//unsigned char rrn[13];
//unsigned char stan[7];
//unsigned char cardtype[33];
char errCode[17];
//unsigned char receiptData[IUC_ASYNCHPOS_RECEIPT_LENGTH];
};
struct AuthorizationResult {
QString m_id; // max. 36
QString m_docNr; // max. 32
QString m_result; // "OK" or "ERROR"
};
static AsynchBillData m_asyncBillData;
static AuthorizationResult m_authorizationResult;
};
#endif // MESSAGE_HELPER_H_INCLUDED

625
main/aes128.cpp Executable file

@ -0,0 +1,625 @@
/*
* aes128.c
*
* Created: 27.11.2017 13:33:29
* Author: Matthias
*/
#include <aes128.h>
/* the expanded keySize */
#define EXPANDED_KEY_SIZE 176
//int expandedKeySize;
/* the expanded key */
//unsigned char expandedKey[EXPANDED_KEY_SIZE];
/* the cipher key */
//unsigned char key[16];
/* the cipher key size */
enum keySize{
SIZE_16 = 16,
SIZE_24 = 24,
SIZE_32 = 32
};
//enum keySize size;
unsigned char sbox[256] = {
//0 1 2 3 4 5 6 7 8 9 A B C D E F
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, //0
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, //1
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, //2
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, //3
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, //4
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, //5
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, //6
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, //7
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, //8
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, //9
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, //A
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, //B
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, //C
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, //D
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, //E
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; //F
unsigned char rsbox[256] =
{ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb
, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb
, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e
, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25
, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92
, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84
, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06
, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b
, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73
, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e
, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b
, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4
, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f
, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef
, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61
, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };
unsigned char Rcon[256] = {
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d,
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab,
0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d,
0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25,
0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01,
0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d,
0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa,
0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a,
0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02,
0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f,
0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5,
0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33,
0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d};
void aes_init() {
//UINT uitemp = 0;
/* the expanded keySize */
//expandedKeySize = EXPANDED_KEY_SIZE;
/* the cipher key */
//for (uitemp = 0; uitemp < 16; ++uitemp)
//key[uitemp] = 0x00;
/* the cipher key size */
//size = SIZE_16;
}
unsigned char getSBoxValue(unsigned char num)
{
return sbox[num];
}
unsigned char getSBoxInvert(unsigned char num)
{
return rsbox[num];
}
//Key generation
/* Rijndael's key schedule rotate operation
* rotate the word eight bits to the left
*
* rotate(1d2c3a4f) = 2c3a4f1d
*
* word is an char array of size 4 (32 bit)
*/
void rotate(unsigned char *word)
{
unsigned char c;
int i;
c = word[0];
for (i = 0; i < 3; i++)
word[i] = word[i+1];
word[3] = c;
}
unsigned char getRconValue(unsigned char num)
{
return Rcon[num];
}
void core(unsigned char *word, int iteration)
{
int i;
/* rotate the 32-bit word 8 bits to the left */
rotate(word);
/* apply S-Box substitution on all 4 parts of the 32-bit word */
for (i = 0; i < 4; ++i)
{
word[i] = getSBoxValue(word[i]);
}
/* XOR the output of the rcon operation with i to the first part (leftmost) only */
word[0] = word[0]^getRconValue(((unsigned char) iteration));
}
/* Rijndael's key expansion
* expands an 128,192,256 key into an 176,208,240 bytes key
*
* expandedKey is a pointer to an char array of large enough size
* key is a pointer to a non-expanded key
*/
void expandKey(unsigned char *expandedKey,
unsigned char *key,
enum keySize size,
/*size_t*/ unsigned int expandedKeySize)
{
/* current expanded keySize, in bytes */
int currentSize = 0;
int rconIteration = 1;
int i;
unsigned char t[4] = {0,0,0,0}; // temporary 4-byte variable
/* set the 16,24,32 bytes of the expanded key to the input key */
for (i = 0; i < size; i++)
expandedKey[i] = key[i];
currentSize += size;
while (currentSize < expandedKeySize)
{
/* assign the previous 4 bytes to the temporary value t */
for (i = 0; i < 4; i++)
{
t[i] = expandedKey[(currentSize - 4) + i];
}
/* every 16,24,32 bytes we apply the core schedule to t
* and increment rconIteration afterwards
*/
if(currentSize % size == 0)
{
core(t, rconIteration++);
}
/* For 256-bit keys, we add an extra sbox to the calculation */
if(size == SIZE_32 && ((currentSize % size) == 16)) {
for(i = 0; i < 4; i++)
t[i] = getSBoxValue(t[i]);
}
/* We XOR t with the four-byte block 16,24,32 bytes before the new expanded key.
* This becomes the next four bytes in the expanded key.
*/
for(i = 0; i < 4; i++) {
expandedKey[currentSize] = expandedKey[currentSize - size] ^ t[i];
currentSize++;
}
}
}
//Encrypt
void subBytes(unsigned char *state)
{
int i;
/* substitute all the values from the state with the value in the SBox
* using the state value as index for the SBox
*/
for (i = 0; i < 16; i++)
state[i] = getSBoxValue(state[i]);
}
void shiftRow(unsigned char *state, unsigned char nbr)
{
int i, j;
unsigned char tmp;
/* each iteration shifts the row to the left by 1 */
for (i = 0; i < nbr; i++)
{
tmp = state[0];
for (j = 0; j < 3; j++)
state[j] = state[j+1];
state[3] = tmp;
}
}
void shiftRows(unsigned char *state)
{
int i;
/* iterate over the 4 rows and call shiftRow() with that row */
for (i = 0; i < 4; i++)
shiftRow(state+i*4, i);
}
void addRoundKey(unsigned char *state, unsigned char *roundKey)
{
int i;
for (i = 0; i < 16; i++)
state[i] = state[i] ^ roundKey[i] ;
}
unsigned char galois_multiplication(unsigned char a, unsigned char b)
{
unsigned char p = 0;
unsigned char counter;
unsigned char hi_bit_set;
for(counter = 0; counter < 8; counter++) {
if((b & 1) == 1)
p ^= a;
hi_bit_set = (a & 0x80);
a <<= 1;
if(hi_bit_set == 0x80)
a ^= 0x1b;
b >>= 1;
}
return p;
}
void mixColumn(unsigned char *column)
{
unsigned char cpy[4];
int i;
for(i = 0; i < 4; i++)
{
cpy[i] = column[i];
}
column[0] = galois_multiplication(cpy[0],2) ^
galois_multiplication(cpy[3],1) ^
galois_multiplication(cpy[2],1) ^
galois_multiplication(cpy[1],3);
column[1] = galois_multiplication(cpy[1],2) ^
galois_multiplication(cpy[0],1) ^
galois_multiplication(cpy[3],1) ^
galois_multiplication(cpy[2],3);
column[2] = galois_multiplication(cpy[2],2) ^
galois_multiplication(cpy[1],1) ^
galois_multiplication(cpy[0],1) ^
galois_multiplication(cpy[3],3);
column[3] = galois_multiplication(cpy[3],2) ^
galois_multiplication(cpy[2],1) ^
galois_multiplication(cpy[1],1) ^
galois_multiplication(cpy[0],3);
}
void mixColumns(unsigned char *state)
{
int i, j;
unsigned char column[4];
/* iterate over the 4 columns */
for (i = 0; i < 4; i++)
{
/* construct one column by iterating over the 4 rows */
for (j = 0; j < 4; j++)
{
column[j] = state[(j*4)+i];
}
/* apply the mixColumn on one column */
mixColumn(column);
/* put the values back into the state */
for (j = 0; j < 4; j++)
{
state[(j*4)+i] = column[j];
}
}
}
void aes_round(unsigned char *state, unsigned char *roundKey)
{
subBytes(state);
shiftRows(state);
mixColumns(state);
addRoundKey(state, roundKey);
}
void createRoundKey(unsigned char *expandedKey, unsigned char *roundKey)
{
int i,j;
/* iterate over the columns */
for (i = 0; i < 4; i++)
{
/* iterate over the rows */
for (j = 0; j < 4; j++)
roundKey[(i+(j*4))] = expandedKey[(i*4)+j];
}
}
void aes_main(unsigned char *state, unsigned char *expandedKey, int nbrRounds)
{
int i = 0;
unsigned char roundKey[16];
createRoundKey(expandedKey, roundKey);
addRoundKey(state, roundKey);
for (i = 1; i < nbrRounds; i++) {
createRoundKey(expandedKey + 16*i, roundKey);
aes_round(state, roundKey);
}
createRoundKey(expandedKey + 16*nbrRounds, roundKey);
subBytes(state);
shiftRows(state);
addRoundKey(state, roundKey);
}
char aes_encrypt(unsigned char *input,
unsigned char *output,
unsigned char *key
/*, enum keySize size*/)
{
enum keySize size = SIZE_16;
/* the expanded keySize */
int expandedKeySize;
/* the number of rounds */
int nbrRounds = 10; //NOTE: modded
/* the expanded key */
//NOTE: modded: unsigned char *expandedKey = 0x00;
//unsigned char expandedKey[(16*(nbrRounds+1))];
unsigned char expandedKey[176];
/* the 128 bit block to encode */
unsigned char block[16];
int i,j;
/* set the number of rounds */
/*switch (size)
{
case SIZE_16:
nbrRounds = 10;
break;
case SIZE_24:
nbrRounds = 12;
break;
case SIZE_32:
nbrRounds = 14;
break;
default:
return 1; //UNKNOWN_KEYSIZE;
break;
}*/ //NOTE: modded
expandedKeySize = (16*(nbrRounds+1));
/*if ((expandedKey = malloc(expandedKeySize * sizeof(char))) == NULL)
{
return MEMORY_ALLOCATION_PROBLEM;
}*/
/* Set the block values, for the block:
* a0,0 a0,1 a0,2 a0,3
* a1,0 a1,1 a1,2 a1,3
* a2,0 a2,1 a2,2 a2,3
* a3,0 a3,1 a3,2 a3,3
* the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3
*/
/* iterate over the columns */
for (i = 0; i < 4; i++)
{
/* iterate over the rows */
for (j = 0; j < 4; j++)
block[(i+(j*4))] = input[(i*4)+j];
}
/* expand the key into an 176, 208, 240 bytes key */
expandKey(expandedKey, key, size, expandedKeySize);
/* encrypt the block using the expandedKey */
aes_main(block, expandedKey, nbrRounds);
/* unmap the block again into the output */
for (i = 0; i < 4; i++)
{
/* iterate over the rows */
for (j = 0; j < 4; j++)
output[(i*4)+j] = block[(i+(j*4))];
}
return 0;
}
//Decrypt
void invSubBytes(unsigned char *state)
{
int i;
/* substitute all the values from the state with the value in the SBox
* using the state value as index for the SBox
*/
for (i = 0; i < 16; i++)
state[i] = getSBoxInvert(state[i]);
}
void invShiftRow(unsigned char *state, unsigned char nbr)
{
int i, j;
unsigned char tmp;
/* each iteration shifts the row to the right by 1 */
for (i = 0; i < nbr; i++)
{
tmp = state[3];
for (j = 3; j > 0; j--)
state[j] = state[j-1];
state[0] = tmp;
}
}
void invShiftRows(unsigned char *state)
{
int i;
/* iterate over the 4 rows and call invShiftRow() with that row */
for (i = 0; i < 4; i++)
invShiftRow(state+i*4, i);
}
void invMixColumn(unsigned char *column)
{
unsigned char cpy[4];
int i;
for(i = 0; i < 4; i++)
{
cpy[i] = column[i];
}
column[0] = galois_multiplication(cpy[0],14) ^
galois_multiplication(cpy[3],9) ^
galois_multiplication(cpy[2],13) ^
galois_multiplication(cpy[1],11);
column[1] = galois_multiplication(cpy[1],14) ^
galois_multiplication(cpy[0],9) ^
galois_multiplication(cpy[3],13) ^
galois_multiplication(cpy[2],11);
column[2] = galois_multiplication(cpy[2],14) ^
galois_multiplication(cpy[1],9) ^
galois_multiplication(cpy[0],13) ^
galois_multiplication(cpy[3],11);
column[3] = galois_multiplication(cpy[3],14) ^
galois_multiplication(cpy[2],9) ^
galois_multiplication(cpy[1],13) ^
galois_multiplication(cpy[0],11);
}
void invMixColumns(unsigned char *state)
{
int i, j;
unsigned char column[4];
/* iterate over the 4 columns */
for (i = 0; i < 4; i++)
{
/* construct one column by iterating over the 4 rows */
for (j = 0; j < 4; j++)
{
column[j] = state[(j*4)+i];
}
/* apply the invMixColumn on one column */
invMixColumn(column);
/* put the values back into the state */
for (j = 0; j < 4; j++)
{
state[(j*4)+i] = column[j];
}
}
}
void aes_invRound(unsigned char *state, unsigned char *roundKey)
{
invShiftRows(state);
invSubBytes(state);
addRoundKey(state, roundKey);
invMixColumns(state);
}
void aes_invMain(unsigned char *state, unsigned char *expandedKey, int nbrRounds)
{
int i = 0;
unsigned char roundKey[16];
createRoundKey(expandedKey + 16*nbrRounds, roundKey);
addRoundKey(state, roundKey);
for (i = nbrRounds-1; i > 0; i--) {
createRoundKey(expandedKey + 16*i, roundKey);
aes_invRound(state, roundKey);
}
createRoundKey(expandedKey, roundKey);
invShiftRows(state);
invSubBytes(state);
addRoundKey(state, roundKey);
}
char aes_decrypt(unsigned char *input,
unsigned char *output,
unsigned char *key
/*´, enum keySize size*/)
{
enum keySize size = SIZE_16;
/* the expanded keySize */
int expandedKeySize;
/* the number of rounds */
int nbrRounds;
/* the expanded key */
unsigned char *expandedKey = 0x00;
/* the 128 bit block to decode */
unsigned char block[16];
int i,j;
/* set the number of rounds */
switch (size)
{
case SIZE_16:
nbrRounds = 10;
break;
case SIZE_24:
nbrRounds = 12;
break;
case SIZE_32:
nbrRounds = 14;
break;
default:
return 1; //UNKNOWN_KEYSIZE;
break;
}
expandedKeySize = (16*(nbrRounds+1));
/*if ((expandedKey = malloc(expandedKeySize * sizeof(char))) == NULL)
{
return MEMORY_ALLOCATION_PROBLEM;
}*/
/* Set the block values, for the block:
* a0,0 a0,1 a0,2 a0,3
* a1,0 a1,1 a1,2 a1,3
* a2,0 a2,1 a2,2 a2,3
* a3,0 a3,1 a3,2 a3,3
* the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3
*/
/* iterate over the columns */
for (i = 0; i < 4; i++)
{
/* iterate over the rows */
for (j = 0; j < 4; j++)
block[(i+(j*4))] = input[(i*4)+j];
}
/* expand the key into an 176, 208, 240 bytes key */
expandKey(expandedKey, key, size, expandedKeySize);
/* decrypt the block using the expandedKey */
aes_invMain(block, expandedKey, nbrRounds);
/* unmap the block again into the output */
for (i = 0; i < 4; i++)
{
/* iterate over the rows */
for (j = 0; j < 4; j++)
output[(i*4)+j] = block[(i+(j*4))];
}
return 0;
}

8
main/aes128.h Executable file

@ -0,0 +1,8 @@
#ifndef AES128_H
#define AES128_H
void aes_init();
char aes_encrypt(unsigned char *input,unsigned char *output,unsigned char *key);
char aes_decrypt(unsigned char *input,unsigned char *output,unsigned char *key);
#endif

2131
main/cc_iuc_asynchpos.cpp Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -27,11 +27,19 @@ CONFIG(debug, debug|release) {
SOURCES += main.cpp SOURCES += main.cpp
# HEADERS +=
# HEADERS += \ OTHER_FILES += \
/opt/ptu5/opt/customer_335/etc/psa_tariff/tariff01.json \
# OTHER_FILES += \ /opt/ptu5/opt/customer_335/etc/psa_tariff/tariff02.json \
/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff01.json \
/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff02.json \
/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff03.json \
/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff04.json \
/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff05.json \
/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff06.json \
/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff07.json \
/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff08.json

96
main/terminal_utils.cpp Normal file

@ -0,0 +1,96 @@
#include "terminal_utils.h"
#include <atomic>
#include <cstring>
#include <endian.h>
#include <QString>
#include <QByteArray>
#include <QDebug>
namespace TU {
char const *terminalStatus(uint8_t status) {
switch (status) {
case TERMINAL_CB2_KEYS_NOT_PRESENT:
return "CB2 KEYS NOT PRESENT";
case TERMINAL_NO_BANKING_PARAMETERS_PRESENT:
return "NO BANKING PARAMETERS PRESENT";
case TERMINAL_IS_BLOCKED:
return "TERMINAL IS BLOCKED";
case TERMINAL_NOT_OPERATIVE:
return "TERMINAL NOT OPERATIVE";
case TERMINAL_IS_READY_AND_ACTIVE:
return "TERMINAL IS READY AND ACTIVE";
case TERMINAL_IS_READY_AND_NOT_ACTIVE:
return "TERMINAL IS READY AND *NOT* ACTIVE";
case TERMINAL_LOG_FULL:
return "TERMINAL LOG IS FULL";
default:
return "";
}
}
QByteArray int2Hex(int i) {
return QByteArray::fromHex(
QString().setNum(i, 16).toLocal8Bit().constData()).toHex();
}
uint16_t getNextTransactionId() {
static std::atomic<int> i{0};
int j = 0;
while ((j = (++i % 100)) == 0); // 1 <= j <= 99
return htobe16(((j / 10) + 0x30) << 8) | ((j % 10) + 0x30);
}
uint32_t crc32(uint32_t crc, unsigned char* pData, size_t len) {
qCritical() << "updateCRC" << QByteArray((char *)pData, len).toHex();
int i = 0;
int j = 0;
unsigned char ucCarry = 0x00;
crc = ~crc;
while (len > 0) {
uint32_t const c = pData[i];
crc ^= c;
++i;
for (j = 0; j < 8; ++j) {
ucCarry = crc & 1;
crc >>= 1;
if (ucCarry) {
crc ^= 0xedb88320;
}
}
--len;
}
return ~crc;
}
uint32_t crc32(QByteArray const &ba) {
uint32_t crc = 0;
return crc32(crc, (uint8_t *)ba.data(), ba.size());
}
char lrc(QByteArray const &ba) {
char crc = 0;
for (int i = 0; i < ba.size(); ++i) {
crc ^= ba[i];
}
return crc;
}
bool isBigEndian() {
union {
uint32_t i;
char c[4];
} bint = {0x01020304};
return bint.c[0] == 1;
}
}

31
main/terminal_utils.h Normal file

@ -0,0 +1,31 @@
#ifndef TERMINAL_UTILS_H_INCLUDED
#define TERMINAL_UTILS_H_INCLUDED
#include <cinttypes>
#include <QByteArray>
namespace TU {
enum STATUS : uint8_t {
TERMINAL_CB2_KEYS_NOT_PRESENT = 0x30,
TERMINAL_NO_BANKING_PARAMETERS_PRESENT = 0x31,
TERMINAL_IS_BLOCKED = 0x32,
TERMINAL_NOT_OPERATIVE = 0x33,
TERMINAL_IS_READY_AND_ACTIVE = 0x34,
TERMINAL_IS_READY_AND_NOT_ACTIVE = 0x35,
TERMINAL_LOG_FULL = 0x36
};
char const *terminalStatus(uint8_t status);
QByteArray int2Hex(int i);
uint16_t getNextTransactionId();
//uint32_t crc32(const char *s, size_t n);
//uint32_t crc32(QByteArray const &ba);
uint32_t crc32(QByteArray const &ba);
uint32_t crc32(uint32_t crc, unsigned char* pData, size_t len);
char lrc(QByteArray const &ba);
bool isBigEndian();
}
#endif // TERMINAL_UTILS_H_INCLUDED

1529
out.txt Normal file

File diff suppressed because it is too large Load Diff