ElementTree::ElementPtr stop_service(Session &session, ILogger &logger, const StringDict ¶ms) { string transaction_eid = params.get("transaction_id", ""); if (transaction_eid.size() < 4 || transaction_eid.size() > 64) throw ApiResult(mk_resp("bad_transaction")); Payment payment(EMPTY_DATAOBJ); try { payment = query<Payment>(session).for_update() .filter_by(Payment::c.trans_number == transaction_eid).one(); } catch (const NoDataFound &) { throw ApiResult(mk_resp("bad_transaction")); } if (payment.payment_ts == Value() || payment.cancel_ts != Value()) throw ApiResult(mk_resp("bad_transaction")); Order order = query<Order>(session).for_update() .filter_by(Order::c.id == payment.order->id).one(); if (order.ticket_number != Value()) throw ApiResult(mk_resp("bad_transaction")); int existing_cnt = order.receipts.size(); ElementTree::ElementPtr resp = mk_resp("success"); if (existing_cnt) { YB_ASSERT(existing_cnt == 1); resp->add_json("delta_amount", money2str( order.receipts.begin()->amount)); throw ApiResult(resp); } DateTime now_ts = now(); if (now_ts >= order.paid_until_ts) { resp->add_json("delta_amount", money2str(Decimal(0))); throw ApiResult(resp); } int total_secs_left = (int)datetime_diff(now_ts, order.paid_until_ts) - 1; int duration_left = (total_secs_left / (15 * 60)) * 15; // rounded minutes Decimal price_per_minute = order.paid_amount / Decimal(datetime_diff( order.start_ts, order.paid_until_ts) / 60); Decimal delta_amount = (duration_left * price_per_minute).round(2); logger.debug("total_seconds_left=" + to_string(total_secs_left) + " duration_left=" + to_string(duration_left) + " price=" + money2str(price_per_minute) + " delta=" + money2str(delta_amount)); create_account_receipt(session, order.user_eid, order, delta_amount); resp->add_json("delta_amount", money2str(delta_amount)); return resp; }
ElementTree::ElementPtr get_service_info(Session &session, ILogger &logger, const StringDict ¶ms) { string service_descr_str = params["service_descr"]; string user_eid = params.get("user_id", ""); if (user_eid.empty()) throw ApiResult(mk_resp("not_available", "invalid_user_id")); StringDict service_descr = json2dict(service_descr_str); logger.debug("service_descr: " + dict2str(service_descr)); Product parking; try { string parking_name = service_descr["parking_id"]; parking = query<Product>(session) .filter_by(Product::c.name == parking_name).one(); } catch (const NoDataFound &) { throw ApiResult(mk_resp("not_available", "invalid_parking_id")); } Decimal price, hours; Order order(get_hours_and_price(session, logger, service_descr, parking, false, hours, price)); ElementTree::ElementPtr resp = mk_resp("success"); resp->add_json("price", money2str(price)); ElementTree::ElementPtr info = resp->add_json_dict("info"); info->add_json("available_places", parking.places_avail.value()); if (!order.is_empty()) { info->add_json("start_ts", timestamp2str(datetime2timestamp(order.start_ts))); if (service_descr.has("user_ticket")) info->add_json("paid_duration", Decimal(datetime_diff(order.start_ts, order.paid_until_ts) / 60).round()); } else { info->add_json("start_ts", timestamp2str(datetime2timestamp(now()))); } info->add_json("duration", (hours * 60).round()); info->add_json("balance", money2str( get_account_balance(session, user_eid))); throw ApiResult(resp); }
ElementTree::ElementPtr create_reservation(Session &session, ILogger &logger, const StringDict ¶ms) { string user_eid = params.get("user_id", ""); if (user_eid.empty()) throw ApiResult(mk_resp("not_available", "invalid_user_id")); StringDict service_descr = json2dict(params["service_descr"]); logger.debug("service_descr: " + dict2str(service_descr)); Product parking(EMPTY_DATAOBJ); try { string parking_name = service_descr["parking_id"]; parking = query<Product>(session).for_update() .filter_by(Product::c.name == parking_name).one(); } catch (const NoDataFound &) { throw ApiResult(mk_resp("not_available", "invalid_parking_id")); } string plate_number = service_descr.get("registration_plate", ""); if (plate_number.empty()) throw ApiResult(mk_resp("not_available", "invalid_registration_plate")); Decimal price0 = Decimal(params["price"]); Decimal pay_from_balance = Decimal(params["pay_from_balance"]); if (pay_from_balance < Decimal(0) || pay_from_balance > price0) throw ApiResult(mk_resp("wrong_price")); string transaction_eid = params.get("transaction_id", ""); if (transaction_eid.size() < 4 || transaction_eid.size() > 64) throw ApiResult(mk_resp("bad_transaction")); try { Payment payment = query<Payment>(session).for_update() .filter_by(Payment::c.trans_number == transaction_eid).one(); if (payment.amount == price0 && *payment.order->product == parking) throw ApiResult(mk_resp("success")); throw ApiResult(mk_resp("wrong_price")); } catch (const NoDataFound &) {} Decimal price, hours; Order order(get_hours_and_price( session, logger, service_descr, parking, true, hours, price)); if (price != price0) throw ApiResult(mk_resp("wrong_price")); if (parking.places_avail == 0) throw ApiResult(mk_resp("not_available")); if (order.is_empty()) { order = Order(session); order.product = Product::Holder(parking); order.user_eid = user_eid; order.plate_number = plate_number; order.start_ts = now(); order.paid_until_ts = order.start_ts; order.price = parking.price; } Payment payment; payment.trans_number = transaction_eid; payment.hours = hours; payment.order = Order::Holder(order); payment.amount = price - pay_from_balance; payment.ts = order.start_ts; payment.save(session); if (pay_from_balance > 0) { create_account_consume(session, user_eid, payment, pay_from_balance, true); } ElementTree::ElementPtr resp = mk_resp("success"); resp->add_json("price", money2str(price)); ElementTree::ElementPtr info = resp->add_json_dict("info"); info->add_json("start_ts", timestamp2str(datetime2timestamp(order.start_ts))); info->add_json("duration", (hours * 60).round()); if (service_descr.has("user_ticket")) info->add_json("paid_duration", Decimal(0)); return resp; }