Service Order¶
ServiceOrders(perfdb)
¶
Class used for handling Service Order data. Can be accessed via perfdb.service_orders.
Parameters:
Source code in echo_postgres/service_orders.py
def __init__(self, perfdb: e_pg.PerfDB) -> None:
"""Class used for handling Service Order data. Can be accessed via `perfdb.service_orders`.
Parameters
----------
perfdb : PerfDB
Top level object carrying all functionality and the connection handler.
"""
super().__init__(perfdb)
from .service_order_notes import ServiceOrderNotes
from .service_order_status import ServiceOrderStatus
# * subclasses
self.notes = ServiceOrderNotes(perfdb)
self.status = ServiceOrderStatus(perfdb)
delete(names, descriptions=None, sap_ids=None, statuses=None, filter_type='and')
¶
Deletes service orders from the database.
Be cautious when using this method, as it will permanently delete data.
Parameters:
-
(names¶list[str] | None) –List of names to retrieve information for.
If None, retrieves information for all available.
-
(descriptions¶list[str] | None, default:None) –List of descriptions (regex) to retrieve information for.
If None, retrieves information for all available.
-
(sap_ids¶list[int] | None, default:None) –List of SAP IDs to retrieve information for.
If None, retrieves information for all available.
-
(statuses¶list[str] | None, default:None) –List of statuses to retrieve information for.
If None, retrieves information for all available.
-
(filter_type¶Literal['and', 'or'], default:'and') –How to treat multiple filters. Can be one of ["and", "or"]. By default "and".
Source code in echo_postgres/service_orders.py
@validate_call
def delete(
self,
names: list[str],
descriptions: list[str] | None = None,
sap_ids: list[int] | None = None,
statuses: list[str] | None = None,
filter_type: Literal["and", "or"] = "and",
) -> None:
"""Deletes service orders from the database.
Be cautious when using this method, as it will permanently delete data.
Parameters
----------
names : list[str] | None, optional
List of names to retrieve information for.
If None, retrieves information for all available.
descriptions : list[str] | None, optional
List of descriptions (regex) to retrieve information for.
If None, retrieves information for all available.
sap_ids : list[int] | None, optional
List of SAP IDs to retrieve information for.
If None, retrieves information for all available.
statuses : list[str] | None, optional
List of statuses to retrieve information for.
If None, retrieves information for all available.
filter_type : Literal["and", "or"], optional
How to treat multiple filters. Can be one of ["and", "or"]. By default "and".
"""
# check if at least one name filter is provided
if not any([names, descriptions, sap_ids, statuses]):
raise ValueError("At least one filter must be provided to delete service orders.")
# getting ids to delete
ids = self.get_ids(
names=names,
descriptions=descriptions,
sap_ids=sap_ids,
statuses=statuses,
filter_type=filter_type,
)
if not ids:
logger.debug("No service orders found to delete based on the provided filters.")
return
query = sql.SQL(
"DELETE FROM performance.service_orders WHERE id = ANY({ids})",
).format(
ids=sql.Literal(list(ids.values())),
)
with self._perfdb.conn.reconnect() as conn:
result = conn.execute(query)
rows = result.rowcount if result else 0
logger.debug(f"Deleted {rows} service orders from the database.")
get(names=None, descriptions=None, sap_ids=None, statuses=None, filter_type='and', output_type='dict')
¶
Retrieves Service Order information from the database.
The most useful keys/columns returned are:
- id
- name (index if output_type is DataFrame)
- sap_id
- status_id
- status_name
- status_display_name
- status_sap_name
- description
Parameters:
-
(names¶list[str] | None, default:None) –List of names to retrieve information for.
If None, retrieves information for all available.
-
(descriptions¶list[str] | None, default:None) –List of descriptions (regex) to retrieve information for.
If None, retrieves information for all available.
-
(sap_ids¶list[int] | None, default:None) –List of SAP IDs to retrieve information for.
If None, retrieves information for all available.
-
(statuses¶list[str] | None, default:None) –List of statuses to retrieve information for.
If None, retrieves information for all available.
-
(filter_type¶Literal['and', 'or'], default:'and') –How to treat multiple filters. Can be one of ["and", "or"]. By default "and".
-
(output_type¶Literal['dict', 'DataFrame', 'pl.DataFrame'], default:'dict') –Output type of the data. Can be one of ["dict", "DataFrame", "pl.DataFrame"] By default "dict"
Returns:
-
dict[str, dict[str, Any]]–In case output_type is "dict", returns a dictionary in the format {name: {attribute: value, ...}, ...}
-
DataFrame–In case output_type is "DataFrame", returns a DataFrame with the following format: index = name, columns = [attribute, ...]
-
DataFrame–In case output_type is "pl.DataFrame", returns a Polars DataFrame
Source code in echo_postgres/service_orders.py
@validate_call
def get(
self,
names: list[str] | None = None,
descriptions: list[str] | None = None,
sap_ids: list[int] | None = None,
statuses: list[str] | None = None,
filter_type: Literal["and", "or"] = "and",
output_type: Literal["dict", "DataFrame", "pl.DataFrame"] = "dict",
) -> dict[str, dict[str, Any]] | pd.DataFrame | pl.DataFrame:
"""Retrieves Service Order information from the database.
The most useful keys/columns returned are:
- id
- name (index if output_type is DataFrame)
- sap_id
- status_id
- status_name
- status_display_name
- status_sap_name
- description
Parameters
----------
names : list[str] | None, optional
List of names to retrieve information for.
If None, retrieves information for all available.
descriptions : list[str] | None, optional
List of descriptions (regex) to retrieve information for.
If None, retrieves information for all available.
sap_ids : list[int] | None, optional
List of SAP IDs to retrieve information for.
If None, retrieves information for all available.
statuses : list[str] | None, optional
List of statuses to retrieve information for.
If None, retrieves information for all available.
filter_type : Literal["and", "or"], optional
How to treat multiple filters. Can be one of ["and", "or"]. By default "and".
output_type : Literal["dict", "DataFrame", "pl.DataFrame"], optional
Output type of the data. Can be one of ["dict", "DataFrame", "pl.DataFrame"]
By default "dict"
Returns
-------
dict[str, dict[str, Any]]
In case output_type is "dict", returns a dictionary in the format {name: {attribute: value, ...}, ...}
DataFrame
In case output_type is "DataFrame", returns a DataFrame with the following format: index = name, columns = [attribute, ...]
pl.DataFrame
In case output_type is "pl.DataFrame", returns a Polars DataFrame
"""
where_query = self._check_get_args(
names=names,
descriptions=descriptions,
sap_ids=sap_ids,
statuses=statuses,
filter_type=filter_type,
)
query = sql.SQL(
"SELECT * FROM performance.v_service_orders {where_query} ORDER BY name",
).format(
where_query=where_query,
)
with self._perfdb.conn.reconnect() as conn:
df = conn.read_to_polars(query)
if output_type == "pl.DataFrame":
return df
df = df.to_pandas(use_pyarrow_extension_array=True)
df = df.set_index("name")
if output_type == "DataFrame":
return df
return df.to_dict(orient="index")
get_ids(names=None, descriptions=None, sap_ids=None, statuses=None, filter_type='and')
¶
Retrieves service order ids from the database.
Parameters:
-
(names¶list[str] | None, default:None) –List of names to retrieve information for.
If None, retrieves information for all available.
-
(descriptions¶list[str] | None, default:None) –List of descriptions (regex) to retrieve information for.
If None, retrieves information for all available.
-
(sap_ids¶list[int] | None, default:None) –List of SAP IDs to retrieve information for.
If None, retrieves information for all available.
-
(statuses¶list[str] | None, default:None) –List of statuses to retrieve information for.
If None, retrieves information for all available.
-
(filter_type¶Literal['and', 'or'], default:'and') –How to treat multiple filters. Can be one of ["and", "or"]. By default "and".
Returns:
-
dict[str, int]–A dictionary in the format {name: id, ...}
Source code in echo_postgres/service_orders.py
@validate_call
def get_ids(
self,
names: list[str] | None = None,
descriptions: list[str] | None = None,
sap_ids: list[int] | None = None,
statuses: list[str] | None = None,
filter_type: Literal["and", "or"] = "and",
) -> dict[str, int]:
"""Retrieves service order ids from the database.
Parameters
----------
names : list[str] | None, optional
List of names to retrieve information for.
If None, retrieves information for all available.
descriptions : list[str] | None, optional
List of descriptions (regex) to retrieve information for.
If None, retrieves information for all available.
sap_ids : list[int] | None, optional
List of SAP IDs to retrieve information for.
If None, retrieves information for all available.
statuses : list[str] | None, optional
List of statuses to retrieve information for.
If None, retrieves information for all available.
filter_type : Literal["and", "or"], optional
How to treat multiple filters. Can be one of ["and", "or"]. By default "and".
Returns
-------
dict[str, int]
A dictionary in the format {name: id, ...}
"""
where_query = self._check_get_args(
names=names,
descriptions=descriptions,
sap_ids=sap_ids,
statuses=statuses,
filter_type=filter_type,
)
query = sql.SQL(
"SELECT name, id FROM performance.v_service_orders {where_query} ORDER BY name",
).format(
where_query=where_query,
)
with self._perfdb.conn.reconnect() as conn:
df = conn.read_to_polars(query)
return dict(zip(df["name"].to_list(), df["id"].to_list(), strict=False))
insert(name, description, status_name, sap_id, on_conflict='ignore')
¶
Inserts a new service order, and ignore if the order already exists.
Fields left as None will not be inserted/updated.
Parameters:
-
(name¶str) –Name of the service order to be inserted.
-
(description¶str | None) –Description of the service order to be inserted.
-
(status_name¶str) –Status name of the service order to be inserted.
-
(sap_id¶int) –SAP ID of the service order to be inserted.
-
(on_conflict¶Literal['ignore', 'update'], default:'ignore') –Strategy to handle conflicts when inserting data. Can be one of:
- "ignore": ignores the new data if a conflict occurs (default)
- "update": updates the existing data with the new data in case of conflict
The conflict will be determined based on the name of the service order.
Returns:
-
int | None–
Source code in echo_postgres/service_orders.py
@validate_call
def insert(
self,
name: str,
description: str,
status_name: str,
sap_id: int,
on_conflict: Literal["ignore", "update"] = "ignore",
) -> int | None:
"""Inserts a new service order, and ignore if the order already exists.
Fields left as None will not be inserted/updated.
Parameters
----------
name : str
Name of the service order to be inserted.
description : str | None, optional
Description of the service order to be inserted.
status_name : str
Status name of the service order to be inserted.
sap_id : int
SAP ID of the service order to be inserted.
on_conflict : Literal["ignore", "update"], optional
Strategy to handle conflicts when inserting data. Can be one of:
- "ignore": ignores the new data if a conflict occurs (default)
- "update": updates the existing data with the new data in case of conflict
The conflict will be determined based on the name of the service order.
Returns
-------
int | None
"""
# get the status id from the status name
status_dict = self.status.get_ids(names=[status_name])
if status_name not in status_dict:
raise ValueError(f"Status name '{status_name}' not found in the database.")
status_id = status_dict[status_name]
query = sql.SQL(
"""
INSERT INTO performance.service_orders (name, description, status_id, sap_id)
VALUES ({service_order_name}, {service_order_description}, {service_order_status_id}, {service_order_sap_id})
ON CONFLICT (name) DO {conflict_action}
RETURNING id
""",
).format(
service_order_name=sql.Literal(name),
service_order_description=sql.Literal(description),
service_order_status_id=sql.Literal(status_id),
service_order_sap_id=sql.Literal(sap_id),
conflict_action=sql.SQL(
"NOTHING"
if on_conflict == "ignore"
else "UPDATE SET description = EXCLUDED.description, status_id = EXCLUDED.status_id, sap_id = EXCLUDED.sap_id",
),
)
with self._perfdb.conn.reconnect() as conn:
result = conn.execute(query)
row = result.fetchone()
service_order_id = row[0] if row else None
logger.debug(
f"Inserted Service Order: {name} - ID: {service_order_id}",
)
return service_order_id