diff --git a/oda_wd_client/base/types.py b/oda_wd_client/base/types.py index f36517b..c03484c 100644 --- a/oda_wd_client/base/types.py +++ b/oda_wd_client/base/types.py @@ -15,11 +15,19 @@ class WorkdayReferenceBaseModel(BaseModel): workday_parent_id: str | None = None workday_parent_type: str | None = None + # This is the name of the class in Workday. Usually ends with "Object" (i.e. "SupplierObject") + _class_name: str | None = None + def wd_object( self, client, - class_name: str, + class_name: str | None = None, ) -> sudsobject.Object: + class_name = class_name or self._class_name + assert ( + class_name + ), "WD Class name must be supplied on class or call to wd_object" + ref_obj = client.factory(f"ns0:{class_name}Type") id_obj = client.factory(f"ns0:{class_name}IDType") id_obj.value = self.workday_id diff --git a/oda_wd_client/service/financial_management/types.py b/oda_wd_client/service/financial_management/types.py index bb24fa8..345f6c0 100644 --- a/oda_wd_client/service/financial_management/types.py +++ b/oda_wd_client/service/financial_management/types.py @@ -33,6 +33,7 @@ class ConversionRateType(BaseModel): class Currency(WorkdayReferenceBaseModel): + _class_name = "CurrencyObject" workday_id: str = Field(max_length=3, alias="currency_code") workday_id_type: Literal["Currency_ID"] = "Currency_ID" description: str | None = None @@ -40,6 +41,7 @@ class Currency(WorkdayReferenceBaseModel): class Company(WorkdayReferenceBaseModel): + _class_name = "CompanyObject" workday_id: str workday_id_type: Literal["Company_Reference_ID"] = "Company_Reference_ID" name: str diff --git a/oda_wd_client/service/resource_management/types.py b/oda_wd_client/service/resource_management/types.py index f2b0f9d..a5f408d 100644 --- a/oda_wd_client/service/resource_management/types.py +++ b/oda_wd_client/service/resource_management/types.py @@ -10,6 +10,7 @@ class TaxApplicability(WorkdayReferenceBaseModel): + _class_name = "Tax_ApplicabilityObject" workday_id: str workday_id_type: Literal["Tax_Applicability_ID"] = "Tax_Applicability_ID" # Code is human-readable text but not critical, so we default to empty string @@ -18,11 +19,19 @@ class TaxApplicability(WorkdayReferenceBaseModel): class TaxOption(WorkdayReferenceBaseModel): + _class_name = "Tax_OptionObject" workday_id: str workday_id_type: Literal["Tax_Option_ID"] = "Tax_Option_ID" +class TaxCode(WorkdayReferenceBaseModel): + _class_name = "Tax_CodeObject" + workday_id: str + workday_id_type: Literal["Tax_Code_ID"] = "Tax_Code_ID" + + class Supplier(WorkdayReferenceBaseModel): + _class_name = "SupplierObject" workday_id: str workday_id_type: Literal["Supplier_ID"] = "Supplier_ID" reference_id: str | None @@ -63,9 +72,44 @@ class Supplier(WorkdayReferenceBaseModel): tax_id_us: str | None +class TaxRate(WorkdayReferenceBaseModel): + _class_name = "Tax_RateObject" + workday_id_type: Literal["Tax_Rate_ID"] = "Tax_Rate_ID" + + +class TaxRecoverability(WorkdayReferenceBaseModel): + _class_name = "Tax_RecoverabilityObject" + workday_id_type: Literal[ + "Tax_Recoverability_Object_ID" + ] = "Tax_Recoverability_Object_ID" + + +class SpendCategory(WorkdayReferenceBaseModel): + _class_name = "Spend_CategoryObject" + workday_id_type: Literal["Spend_Category_ID"] = "Spend_Category_ID" + + +class TaxRateOptionsData(BaseModel): + tax_rate: TaxRate + tax_recoverability: TaxRecoverability = TaxRecoverability( + workday_id="Fully_Recoverable" + ) + tax_option: TaxOption = TaxOption(workday_id="CALC_TAX_DUE") + + +class CostCenter(WorkdayReferenceBaseModel): + _class_name = "Accounting_WorktagObject" + workday_id_type: Literal["Cost_Center_Reference_ID"] = "Cost_Center_Reference_ID" + + class SupplierInvoiceLine(BaseModel): order: int | None description: str | None + tax_rate_options_data: TaxRateOptionsData + tax_applicability: TaxApplicability + tax_code: TaxCode + spend_category: SpendCategory + cost_center: CostCenter amount: Decimal = Field(max_digits=18, decimal_places=3) @@ -78,8 +122,7 @@ class SupplierInvoice(BaseModel): due_date: date total_amount: Decimal = Field(max_digits=26, decimal_places=6) tax_amount: Decimal = Field(max_digits=26, decimal_places=6) - # ENTER_TAX_DUE is "Enter tax due to supplier", which is needed to manually set tax amount in invoices - tax_option: TaxOption = TaxOption(workday_id="ENTER_TAX_DUE") + tax_option: TaxOption lines: list[SupplierInvoiceLine] diff --git a/oda_wd_client/service/resource_management/utils.py b/oda_wd_client/service/resource_management/utils.py index 7cf38f8..bf64787 100644 --- a/oda_wd_client/service/resource_management/utils.py +++ b/oda_wd_client/service/resource_management/utils.py @@ -6,7 +6,6 @@ Supplier, SupplierInvoice, SupplierInvoiceLine, - TaxApplicability, ) # Mapping the Workday tax ID types to canonical names used by our model @@ -130,23 +129,35 @@ def workday_supplier_to_pydantic(data: dict) -> Supplier: ) -def _get_wd_invoice_lines_from_invoice(client, lines: list[SupplierInvoiceLine]): +def _get_wd_invoice_lines_from_invoice( + client, lines: list[SupplierInvoiceLine] +) -> list[sudsobject.Object]: returned_lines = [] for line in lines: wd_line = client.factory("ns0:Supplier_Invoice_Line_Replacement_DataType") - # wd_tax = client.factory("ns0:Tax_Rate_Options_DataType") wd_line.Supplier_Invoice_Line_ID = line.order wd_line.Item_Description = line.description wd_line.Extended_Amount = line.amount - - # wd_line.Tax_Rate_Options_Data = wd_tax - test_applicability = TaxApplicability( - workday_id="NOR_Domestic_Purchase_of_Goods_and_Services" - ) - wd_line.Tax_Applicability_Reference = test_applicability.wd_object( - client, "Tax_ApplicabilityObject" + wd_line.Spend_Category_Reference = line.spend_category.wd_object(client) + + # Tax options + wd_tax = client.factory("ns0:Tax_Rate_Options_DataType") + tax_opts = line.tax_rate_options_data + wd_tax.Tax_Rate_1_Reference = tax_opts.tax_rate.wd_object(client) + wd_tax.Tax_Recoverability_1_Reference = tax_opts.tax_recoverability.wd_object( + client ) + wd_tax.Tax_Option_1_Reference = tax_opts.tax_option.wd_object(client) + wd_line.Tax_Rate_Options_Data = wd_tax + + # Tax code + wd_line.Tax_Applicability_Reference = line.tax_applicability.wd_object(client) + wd_line.Tax_Code_Reference = line.tax_code.wd_object(client) + + # Worktags + wd_line.Worktags_Reference.append(line.cost_center.wd_object(client)) + returned_lines.append(wd_line) return returned_lines @@ -167,20 +178,14 @@ def pydantic_supplier_invoice_to_workday( invoice_data.Locked_in_Workday = True invoice_data.Invoice_Number = invoice.invoice_number - invoice_data.Company_Reference = invoice.company.wd_object(client, "CompanyObject") - invoice_data.Currency_Reference = invoice.currency.wd_object( - client, "CurrencyObject" - ) - invoice_data.Supplier_Reference = invoice.supplier.wd_object( - client, "SupplierObject" - ) - invoice_data.Default_Tax_Option_Reference = invoice.tax_option.wd_object( - client, "Tax_OptionObject" - ) + invoice_data.Company_Reference = invoice.company.wd_object(client) + invoice_data.Currency_Reference = invoice.currency.wd_object(client) + invoice_data.Supplier_Reference = invoice.supplier.wd_object(client) + invoice_data.Default_Tax_Option_Reference = invoice.tax_option.wd_object(client) invoice_data.Invoice_Date = str(invoice.invoice_date) invoice_data.Due_Date_Override = str(invoice.due_date) invoice_data.Control_Amount_Total = invoice.total_amount - invoice_data.Tax_Amount = invoice.tax_amount + # invoice_data.Tax_Amount = invoice.tax_amount # invoice_data.Attachment_Data = _get_wd_attachment_data_from_invoice(invoice) invoice_data.Invoice_Line_Replacement_Data = _get_wd_invoice_lines_from_invoice( client, invoice.lines diff --git a/oda_wd_client/types/resource_management.py b/oda_wd_client/types/resource_management.py index a832c38..2f50324 100644 --- a/oda_wd_client/types/resource_management.py +++ b/oda_wd_client/types/resource_management.py @@ -1,15 +1,27 @@ from oda_wd_client.service.resource_management.types import ( + CostCenter, + SpendCategory, Supplier, SupplierInvoice, SupplierInvoiceLine, TaxApplicability, + TaxCode, TaxOption, + TaxRate, + TaxRateOptionsData, + TaxRecoverability, ) __all__ = [ - "TaxApplicability", - "TaxOption", + "CostCenter", + "SpendCategory", "Supplier", "SupplierInvoice", "SupplierInvoiceLine", + "TaxApplicability", + "TaxCode", + "TaxOption", + "TaxRate", + "TaxRateOptionsData", + "TaxRecoverability", ] diff --git a/pyproject.toml b/pyproject.toml index b94eafd..05463fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "oda-wd-client" -version = "0.0.1" +version = "0.0.2" description = "A library for interacting with Workday from Python" authors = [ "Karl Fredrik Haugland ",