From 306206f542e5ac920d2db9419d86bcad9204ef3a Mon Sep 17 00:00:00 2001
From: Casper3667 <8396443+Casper3667@users.noreply.github.com>
Date: Mon, 2 Feb 2026 00:29:38 +0100
Subject: [PATCH] Operations delivery app fixes and improvements (#21720)
A small bundle of fixes with what is displayed, as mentioned in the
changelog.
Notable changes:
- It is now possible to charge department accounts directly using it.
The one doing it is logged in the transaction log for that account so
command can still go and check it. This was a feature I have been
requested repeatedly to make by operations member, to help encourage
people to buy more things for their department. Only a hangar tech
should be able to change the account that is charged as well.
- The delivery and pay buttons are now separate in the delivery app,
permitting someone to pay without having it delivered, or have it
delivered without paying. This also fixes a bug that paying before it
gets shipped to the Horizon could get an order permanently stuck as
being shipped & paid but not delivered.
---
code/datums/cargo.dm | 15 +-
code/modules/cooking/machinery/commissary.dm | 4 +-
code/modules/economy/quikpay.dm | 4 +-
.../programs/civilian/cargo_delivery.dm | 75 ++++++---
.../OperationsDeliveryImprovements.yml | 12 ++
.../tgui/interfaces/CargoDelivery.tsx | 56 ++++---
tgui/packages/tgui/interfaces/QuikPay.tsx | 153 +++++++++++-------
7 files changed, 201 insertions(+), 118 deletions(-)
create mode 100644 html/changelogs/OperationsDeliveryImprovements.yml
diff --git a/code/datums/cargo.dm b/code/datums/cargo.dm
index b86dc3f663d..31e055de4a6 100644
--- a/code/datums/cargo.dm
+++ b/code/datums/cargo.dm
@@ -42,9 +42,8 @@
// Returns a list of all the objects in the order - Formatted as a list to be json_encoded
/datum/cargo_order/proc/get_object_list()
var/list/object_list = list()
- for (var/datum/cargo_order_item/coi in items)
- for(var/atom/object in coi.ci.items)
- object_list.Add(object.name)
+ for(var/item in get_item_list())
+ object_list.Add(item["name"])
return object_list
// Gets a list of the order data - Formatted as list to be json_encoded
@@ -253,7 +252,7 @@
if(time_shipped)
order_data += "Shipped at: [time_shipped] "
if(received_by)
- order_data += "Received by: "
+ order_data += "Received by: [received_by] "
order_data += "Delivered at: [time_delivered] "
order_data += "
"
order_data += "Order ID: [order_id] "
@@ -276,7 +275,7 @@
order_data += "[item["name"]]: [item["price"]] "
order_data += "Crate Fee: [SScargo.get_cratefee()] "
order_data += "Handling Fee: [SScargo.get_handlingfee()] "
- order_data += "Shuttle Fee: [get_shipment_cost()] "
+ order_data += "Supplier Fee: [get_shipment_cost()] "
order_data += ""
return order_data.Join("")
@@ -338,7 +337,7 @@
time_shipped = worldtime2text()
//Marks a order as delivered - Returns a status message
-/datum/cargo_order/proc/set_delivered(var/user_name, var/user_id, var/paid=0)
+/datum/cargo_order/proc/set_delivered(var/user_name, var/user_id)
if(user_id <= 0)
user_id = null
if(status == "shipped")
@@ -346,8 +345,6 @@
time_delivered = worldtime2text()
received_by = user_name
received_by_id = user_id
- if(paid)
- set_paid(user_name, user_id)
return "The order has been delivered"
else
return "The order could not be delivered - Invalid Status"
@@ -443,7 +440,7 @@
invoice_data += "Shuttle Data
"
invoice_data += ""
invoice_data += ""
- invoice_data += "Shuttle Fee:: "
+ invoice_data += "Supplier fee:: "
invoice_data += "[shuttle_fee] "
invoice_data += " "
invoice_data += ""
diff --git a/code/modules/cooking/machinery/commissary.dm b/code/modules/cooking/machinery/commissary.dm
index c8eb1ff99fd..b7b719b360f 100644
--- a/code/modules/cooking/machinery/commissary.dm
+++ b/code/modules/cooking/machinery/commissary.dm
@@ -291,7 +291,7 @@
/obj/structure/cash_register/commissary/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, "QuikPay", "Idris Quik-Pay Register", 400, 400)
+ ui = new(user, src, "QuikPay", "Idris Quik-Pay Register", 550, 550)
ui.open()
/obj/structure/cash_register/commissary/ui_data(var/mob/user)
@@ -349,7 +349,7 @@
if(L["name"] == params["buying"])
L["amount"]++
return TRUE
- buying += list(list("name" = params["buying"], "amount" = params["amount"]))
+ buying += list(list("name" = params["buying"], "amount" = params["amount"], "price" = items_to_price[params["buying"]]))
if("removal")
var/index = 0
diff --git a/code/modules/economy/quikpay.dm b/code/modules/economy/quikpay.dm
index 12d92abcabb..c8451d39227 100644
--- a/code/modules/economy/quikpay.dm
+++ b/code/modules/economy/quikpay.dm
@@ -117,7 +117,7 @@
/obj/item/quikpay/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, "QuikPay", "Idris Quik-Pay", 400, 400)
+ ui = new(user, src, "QuikPay", "Idris Quik-Pay", 550, 550)
ui.open()
/obj/item/quikpay/ui_data(var/mob/user)
@@ -176,7 +176,7 @@
if(L["name"] == params["buying"])
L["amount"]++
return TRUE
- buying += list(list("name" = params["buying"], "amount" = params["amount"]))
+ buying += list(list("name" = params["buying"], "amount" = params["amount"], "price" = items_to_price[params["buying"]]))
if("removal")
var/index = 0
diff --git a/code/modules/modular_computers/file_system/programs/civilian/cargo_delivery.dm b/code/modules/modular_computers/file_system/programs/civilian/cargo_delivery.dm
index 6fb869794fa..a6665c7fa9c 100644
--- a/code/modules/modular_computers/file_system/programs/civilian/cargo_delivery.dm
+++ b/code/modules/modular_computers/file_system/programs/civilian/cargo_delivery.dm
@@ -16,6 +16,7 @@
var/list/order_details = list() //Order Details for the order
var/datum/cargo_order/co
var/mod_mode = TRUE //If it can be used to pay for orders
+ var/destinationact = "Personal"
/datum/computer_file/program/civilian/cargodelivery/ui_data(mob/user)
var/list/data = initial_data()
@@ -46,6 +47,8 @@
//Pass the status message along
data["status_message"] = status_message
+ data["paying_account"] = destinationact
+
return data
/datum/computer_file/program/civilian/cargodelivery/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
@@ -55,18 +58,35 @@
var/obj/item/card/id/I = usr.GetIdCard()
- //Check if we want to deliver or pay
- //If we are at the status shipped, then only the confirm delivery and pay button should be shown (deliver)
- //If the status is not shipped, then only show the pay button as we can not confirm that it has been paid so far
- //Everyone can pay / confirm delivery
if(action == "deliver")
- order_details = co.get_list()
- //Check if its already delivered
- if(order_details["status"] == "delivered" && !order_details["needs_payment"])
- status_message = "Unable to Deliver - Order has already been delivered and paid for."
+ if(computer && computer.card_slot && computer.network_card)
+ var/obj/item/card/id/id_card
+ if(computer.card_slot?.stored_card)
+ id_card = computer.card_slot.stored_card
+ if(!id_card?.registered_name)
+ status_message = "Card Error: Invalid ID Card in Card Reader"
+ return TRUE
+ order_details = co.get_list()
+
+ //Check if its already delivered
+ if(order_details["status"] == "delivered")
+ status_message = "Unable to Deliver - Order has already been delivered."
+ return TRUE
+
+ //If a payment is not needed and we are at the status shipped, then confirm the delivery
+ else if(order_details["status"] == "shipped")
+ playsound(computer, 'sound/machines/chime.ogg', 50, TRUE)
+ status_message = co.set_delivered(GetNameAndAssignmentFromId(id_card), usr.character_id)
+ order_details = co.get_list()
+ else
+ status_message = "The order is not yet shipped."
+ return TRUE
+ else
+ status_message = "Unable to process - Network Card or Card Reader Missing"
return TRUE
+ if(action == "pay")
if(computer && computer.card_slot && computer.network_card)
var/using_id = FALSE
var/obj/item/card/id/id_card
@@ -77,6 +97,13 @@
using_id = FALSE
status_message = "Card Error: Invalid ID Card in Card Reader"
+ order_details = co.get_list()
+
+ //Check if its already paid for
+ if(!order_details["needs_payment"])
+ status_message = "Unable to pay - Order has already been paid for."
+ return TRUE
+
var/obj/item/spacecash/ewallet/charge_card
if(!using_id)
if(isliving(usr))
@@ -85,14 +112,18 @@
if(!istype(charge_card))
return TRUE
- //Check if a payment is required
if(order_details["needs_payment"])
var/transaction_amount = order_details["price_customer"]
var/transaction_purpose = "Cargo Order #[order_details["order_id"]]"
var/transaction_terminal = "Modular Computer #[computer.network_card.identification_id]"
if(using_id)
- var/status = SSeconomy.transfer_money(id_card.associated_account_number, SScargo.supply_account.account_number,transaction_purpose,transaction_terminal,transaction_amount,null,usr)
+ var/status
+ if(destinationact == "Personal")
+ status = SSeconomy.transfer_money(id_card.associated_account_number, SScargo.supply_account.account_number,transaction_purpose,transaction_terminal,transaction_amount,null,usr)
+ else
+ transaction_purpose = "Cargo Order #[order_details["order_id"]] by [id_card.registered_name]"
+ status = SSeconomy.transfer_money(SSeconomy.get_department_account(destinationact)?.account_number, SScargo.supply_account.account_number,transaction_purpose,transaction_terminal,transaction_amount,null,usr)
if(status)
status_message = status
return TRUE
@@ -106,22 +137,10 @@
charge_card.worth -= transaction_amount
playsound(computer, 'sound/machines/chime.ogg', 50, TRUE)
-
- //Check if we have delivered it aswell or only paid
- if(order_details["status"] == "shipped")
- status_message = co.set_delivered(GetNameAndAssignmentFromId(I), usr.character_id, 1)
- else
- status_message = co.set_paid(GetNameAndAssignmentFromId(I), usr.character_id)
+ status_message = co.set_paid(GetNameAndAssignmentFromId(id_card), usr.character_id)
order_details = co.get_list()
-
- else
- //If a payment is not needed and we are at the status shipped, then confirm the delivery
- if(order_details["status"] == "shipped")
- playsound(computer, 'sound/machines/chime.ogg', 50, TRUE)
- status_message = co.set_delivered(GetNameAndAssignmentFromId(I), usr.character_id, 0)
- order_details = co.get_list()
else
- status_message = "Unable to process - Network Card or Cardreader Missing"
+ status_message = "Unable to process - Network Card or Card Reader Missing"
return TRUE
@@ -147,3 +166,11 @@
else
page = "overview_main" //fall back to overview_main if a unknown page has been supplied
return TRUE
+ if(action == "accountselect")
+ var/list/choices = assoc_to_keys(SSeconomy.department_accounts)
+ choices += "Personal"
+ var/dest = tgui_input_list(usr, "What account would you like to select?", "Destination Account", choices)
+ if(!dest)
+ return FALSE
+ destinationact = dest
+ return TRUE
diff --git a/html/changelogs/OperationsDeliveryImprovements.yml b/html/changelogs/OperationsDeliveryImprovements.yml
new file mode 100644
index 00000000000..9212e12469e
--- /dev/null
+++ b/html/changelogs/OperationsDeliveryImprovements.yml
@@ -0,0 +1,12 @@
+author: TheGreyWolf
+
+delete-after: True
+
+changes:
+ - rscadd: "Added the ability to charge department accounts directly for operation orders through the operations delivery app, without command presence required."
+ - rscadd: "Separated the delivery and the pay buttons in the operations delivery app."
+ - bugfix: "Fixed the display of who accepted a delivery order when printing an invoice."
+ - bugfix: "Prices shown on the delivery app are now correct."
+ - bugfix: "The paper spawning in crates from the cargo elevator now properly show the supposed contents."
+ - rscadd: "The quikpay ui was updated."
+
diff --git a/tgui/packages/tgui/interfaces/CargoDelivery.tsx b/tgui/packages/tgui/interfaces/CargoDelivery.tsx
index bbaf284bb07..4ed762ed7da 100644
--- a/tgui/packages/tgui/interfaces/CargoDelivery.tsx
+++ b/tgui/packages/tgui/interfaces/CargoDelivery.tsx
@@ -15,6 +15,7 @@ export type CargoData = {
order_details: Order;
page: string;
status_message: string;
+ paying_account: string;
};
type Order = {
@@ -160,7 +161,7 @@ export const Overview = (props, context) => {
: 'Unauthorised'}
- {data.order_details.price}.toFixed(2) 电
+ {data.order_details.price.toFixed(2)} 电
{data.order_details.price_cargo.toFixed(2)} 电
@@ -168,9 +169,6 @@ export const Overview = (props, context) => {
{data.order_details.price_customer.toFixed(2)} 电
-
- {data.order_details.price_customer.toFixed(2)} 电
-
{data.order_details.time_submitted}
@@ -223,29 +221,41 @@ export const Payment = (props, context) => {
act('deliver', { deliver: 'true' })}
- />
+ <>
+ act('accountselect')}
+ />
+ act('deliver', { deliver: 'true' })}
+ />
+ act('pay', { deliver: 'true' })}
+ />
+ >
}
>
- {data.order_details.price.toFixed(2)} 电
+ {data.order_details.price_customer.toFixed(2)} 电
+
+
+ {data.paying_account}
{data.order_details.ordered_by}
diff --git a/tgui/packages/tgui/interfaces/QuikPay.tsx b/tgui/packages/tgui/interfaces/QuikPay.tsx
index ce7f1213d56..fc42068c4fb 100644
--- a/tgui/packages/tgui/interfaces/QuikPay.tsx
+++ b/tgui/packages/tgui/interfaces/QuikPay.tsx
@@ -6,6 +6,9 @@ import {
Input,
NumberInput,
Section,
+ Flex,
+ Table,
+ Box,
} from '../components';
import { Window } from '../layouts';
@@ -27,6 +30,7 @@ type Item = {
type ItemBuy = {
name: string;
amount: number;
+ price: number;
};
export const QuikPay = (props, context) => {
@@ -39,12 +43,6 @@ export const QuikPay = (props, context) => {
title="Ordering"
buttons={
<>
- act('locking')}
- />
{data.editmode ? (
{
onClick={() => act('accountselect')}
/>
) : null}
+ act('locking')}
+ />
>
}
>
@@ -69,55 +73,73 @@ export const ItemWindow = (props, context) => {
return (
-
- {data.items.map((item) => (
-
- {item.price.toFixed(2)}电
- act('buy', { buying: item.name, amount: 1 })}
- />
- {data.editmode ? (
+
+
+
+
+ {data.items.map((item) => (
+
+ {item.name}
+
+ {item.price.toFixed(2)}电
+
+
+ {!data.editmode ? (
+
+ act('buy', { buying: item.name, amount: 1 })
+ }
+ />
+ ) : (
+ <>
+
+ act('remove', { removing: item.name })}
+ />
+ >
+ )}
+
+
+ ))}
+
+
+
+
+
+
-
+ {' '}
act('remove', { removing: item.name })}
+ onClick={() => act('clear')}
+ />
+ act('confirm')}
/>
>
- ) : null}
-
- ))}
-
-
- {' '}
- act('clear')}
- />
- act('confirm')}
- />
- >
- }
- >
- {data.buying.length < 1 ? (
- 'Your shopping cart is empty.'
- ) : (
-
- )}
-
+ }
+ >
+ {data.buying.length < 1 ? (
+ 'Your shopping cart is empty.'
+ ) : (
+
+ )}
+
+
+
);
};
@@ -148,17 +170,32 @@ export const CartWindow = (props, context) => {
{data.buying.map((item) => (
-
- x{item.amount}
- act('removal', { removal: item.name })}
- />
-
+
+ {item.name}
+ x{item.amount}
+
+
+ {(item.price * item.amount).toFixed(2)}电
+
+
+ act('removal', { removal: item.name })}
+ />
+
+
+
+
+
))}
- {data.sum ? 'Please swipe your ID to pay.' : ''}
+ {data.sum ? (
+
+ The total is {data.sum.toFixed(2)}电.
+
+ Please swipe your id to pay.
+
+ ) : null}
);
};