SymfWebAPI 1.26.10.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- SymfWebAPI/WebAPI/Interface/BankAccounts/Interfaces/IBankAccountsController/__init__.py +83 -0
- SymfWebAPI/WebAPI/Interface/BankAccounts/Interfaces/IBankAccountsController/_common.py +37 -0
- SymfWebAPI/WebAPI/Interface/BankAccounts/Interfaces/IBankAccountsController/_ops.py +33 -0
- SymfWebAPI/WebAPI/Interface/BankAccounts/Interfaces/__init__.py +21 -0
- SymfWebAPI/WebAPI/Interface/BankAccounts/ViewModels/__init__.py +16 -0
- SymfWebAPI/WebAPI/Interface/BankAccounts/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/Common/Interfaces/ICurrencyRatesController/__init__.py +56 -0
- SymfWebAPI/WebAPI/Interface/Common/Interfaces/ICurrencyRatesController/_common.py +33 -0
- SymfWebAPI/WebAPI/Interface/Common/Interfaces/ICurrencyRatesController/_ops.py +26 -0
- SymfWebAPI/WebAPI/Interface/Common/Interfaces/IDocumentSeriesController/__init__.py +27 -0
- SymfWebAPI/WebAPI/Interface/Common/Interfaces/IDocumentSeriesController/_common.py +10 -0
- SymfWebAPI/WebAPI/Interface/Common/Interfaces/IDocumentSeriesController/_ops.py +13 -0
- SymfWebAPI/WebAPI/Interface/Common/Interfaces/IDocumentTypesController/__init__.py +41 -0
- SymfWebAPI/WebAPI/Interface/Common/Interfaces/IDocumentTypesController/_common.py +17 -0
- SymfWebAPI/WebAPI/Interface/Common/Interfaces/IDocumentTypesController/_ops.py +19 -0
- SymfWebAPI/WebAPI/Interface/Common/Interfaces/IKsefController/__init__.py +40 -0
- SymfWebAPI/WebAPI/Interface/Common/Interfaces/IKsefController/_common.py +20 -0
- SymfWebAPI/WebAPI/Interface/Common/Interfaces/IKsefController/_ops.py +14 -0
- SymfWebAPI/WebAPI/Interface/Common/Interfaces/IPaymentFormsController/__init__.py +27 -0
- SymfWebAPI/WebAPI/Interface/Common/Interfaces/IPaymentFormsController/_common.py +10 -0
- SymfWebAPI/WebAPI/Interface/Common/Interfaces/IPaymentFormsController/_ops.py +13 -0
- SymfWebAPI/WebAPI/Interface/Common/Interfaces/__init__.py +25 -0
- SymfWebAPI/WebAPI/Interface/Common/ViewModels/Aspects/__init__.py +45 -0
- SymfWebAPI/WebAPI/Interface/Common/ViewModels/__init__.py +118 -0
- SymfWebAPI/WebAPI/Interface/Common/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/Contractors/Interfaces/IContractorCardIndexController/__init__.py +54 -0
- SymfWebAPI/WebAPI/Interface/Contractors/Interfaces/IContractorCardIndexController/_common.py +24 -0
- SymfWebAPI/WebAPI/Interface/Contractors/Interfaces/IContractorCardIndexController/_ops.py +17 -0
- SymfWebAPI/WebAPI/Interface/Contractors/Interfaces/IContractorDeliveryAddressesController/__init__.py +55 -0
- SymfWebAPI/WebAPI/Interface/Contractors/Interfaces/IContractorDeliveryAddressesController/_common.py +24 -0
- SymfWebAPI/WebAPI/Interface/Contractors/Interfaces/IContractorDeliveryAddressesController/_ops.py +23 -0
- SymfWebAPI/WebAPI/Interface/Contractors/Interfaces/IContractorDimensions2Controller/__init__.py +27 -0
- SymfWebAPI/WebAPI/Interface/Contractors/Interfaces/IContractorDimensions2Controller/_common.py +10 -0
- SymfWebAPI/WebAPI/Interface/Contractors/Interfaces/IContractorDimensions2Controller/_ops.py +13 -0
- SymfWebAPI/WebAPI/Interface/Contractors/Interfaces/IContractorDimensionsController/__init__.py +41 -0
- SymfWebAPI/WebAPI/Interface/Contractors/Interfaces/IContractorDimensionsController/_common.py +19 -0
- SymfWebAPI/WebAPI/Interface/Contractors/Interfaces/IContractorDimensionsController/_ops.py +17 -0
- SymfWebAPI/WebAPI/Interface/Contractors/Interfaces/IContractorsController/__init__.py +230 -0
- SymfWebAPI/WebAPI/Interface/Contractors/Interfaces/IContractorsController/_common.py +109 -0
- SymfWebAPI/WebAPI/Interface/Contractors/Interfaces/IContractorsController/_ops.py +100 -0
- SymfWebAPI/WebAPI/Interface/Contractors/Interfaces/__init__.py +25 -0
- SymfWebAPI/WebAPI/Interface/Contractors/ViewModels/__init__.py +64 -0
- SymfWebAPI/WebAPI/Interface/Contractors/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/Dictionaries/Interfaces/IFKDictionariesController/__init__.py +129 -0
- SymfWebAPI/WebAPI/Interface/Dictionaries/Interfaces/IFKDictionariesController/_common.py +59 -0
- SymfWebAPI/WebAPI/Interface/Dictionaries/Interfaces/IFKDictionariesController/_ops.py +48 -0
- SymfWebAPI/WebAPI/Interface/Dictionaries/Interfaces/__init__.py +21 -0
- SymfWebAPI/WebAPI/Interface/Dictionaries/ViewModels/__init__.py +49 -0
- SymfWebAPI/WebAPI/Interface/Dictionaries/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/Enums/FKConfigurator/__init__.py +41 -0
- SymfWebAPI/WebAPI/Interface/Enums/__init__.py +459 -0
- SymfWebAPI/WebAPI/Interface/FKF/AccountsChart/Interfaces/IFKAccountsChartController/__init__.py +42 -0
- SymfWebAPI/WebAPI/Interface/FKF/AccountsChart/Interfaces/IFKAccountsChartController/_common.py +17 -0
- SymfWebAPI/WebAPI/Interface/FKF/AccountsChart/Interfaces/IFKAccountsChartController/_ops.py +20 -0
- SymfWebAPI/WebAPI/Interface/FKF/AccountsChart/Interfaces/__init__.py +21 -0
- SymfWebAPI/WebAPI/Interface/FKF/AccountsChart/ViewModels/__init__.py +30 -0
- SymfWebAPI/WebAPI/Interface/FKF/AccountsChart/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/FKF/Calculations/Interfaces/IFKCalculationsBusinessController/__init__.py +28 -0
- SymfWebAPI/WebAPI/Interface/FKF/Calculations/Interfaces/IFKCalculationsBusinessController/_common.py +9 -0
- SymfWebAPI/WebAPI/Interface/FKF/Calculations/Interfaces/IFKCalculationsBusinessController/_ops.py +14 -0
- SymfWebAPI/WebAPI/Interface/FKF/Calculations/Interfaces/IFKCalculationsController/__init__.py +478 -0
- SymfWebAPI/WebAPI/Interface/FKF/Calculations/Interfaces/IFKCalculationsController/_common.py +353 -0
- SymfWebAPI/WebAPI/Interface/FKF/Calculations/Interfaces/IFKCalculationsController/_ops.py +208 -0
- SymfWebAPI/WebAPI/Interface/FKF/Calculations/Interfaces/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/FKF/Calculations/ViewModels/__init__.py +149 -0
- SymfWebAPI/WebAPI/Interface/FKF/Calculations/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/FKF/Common/Interfaces/IFKCurrenciesTablesController/__init__.py +56 -0
- SymfWebAPI/WebAPI/Interface/FKF/Common/Interfaces/IFKCurrenciesTablesController/_common.py +33 -0
- SymfWebAPI/WebAPI/Interface/FKF/Common/Interfaces/IFKCurrenciesTablesController/_ops.py +26 -0
- SymfWebAPI/WebAPI/Interface/FKF/Common/Interfaces/IFKYearsController/__init__.py +27 -0
- SymfWebAPI/WebAPI/Interface/FKF/Common/Interfaces/IFKYearsController/_common.py +9 -0
- SymfWebAPI/WebAPI/Interface/FKF/Common/Interfaces/IFKYearsController/_ops.py +12 -0
- SymfWebAPI/WebAPI/Interface/FKF/Common/Interfaces/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/FKF/Common/ViewModels/CriteriaFilter/__init__.py +14 -0
- SymfWebAPI/WebAPI/Interface/FKF/Common/ViewModels/__init__.py +50 -0
- SymfWebAPI/WebAPI/Interface/FKF/Common/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/FKF/Contractors/Interfaces/IFKContractorDimensions2Controller/__init__.py +55 -0
- SymfWebAPI/WebAPI/Interface/FKF/Contractors/Interfaces/IFKContractorDimensions2Controller/_common.py +24 -0
- SymfWebAPI/WebAPI/Interface/FKF/Contractors/Interfaces/IFKContractorDimensions2Controller/_ops.py +25 -0
- SymfWebAPI/WebAPI/Interface/FKF/Contractors/Interfaces/IFKContractorDimensionsController/__init__.py +97 -0
- SymfWebAPI/WebAPI/Interface/FKF/Contractors/Interfaces/IFKContractorDimensionsController/_common.py +47 -0
- SymfWebAPI/WebAPI/Interface/FKF/Contractors/Interfaces/IFKContractorDimensionsController/_ops.py +37 -0
- SymfWebAPI/WebAPI/Interface/FKF/Contractors/Interfaces/IFKContractorsController/__init__.py +158 -0
- SymfWebAPI/WebAPI/Interface/FKF/Contractors/Interfaces/IFKContractorsController/_common.py +73 -0
- SymfWebAPI/WebAPI/Interface/FKF/Contractors/Interfaces/IFKContractorsController/_ops.py +70 -0
- SymfWebAPI/WebAPI/Interface/FKF/Contractors/Interfaces/__init__.py +23 -0
- SymfWebAPI/WebAPI/Interface/FKF/Contractors/ViewModels/V2026_1/__init__.py +35 -0
- SymfWebAPI/WebAPI/Interface/FKF/Contractors/ViewModels/__init__.py +79 -0
- SymfWebAPI/WebAPI/Interface/FKF/Contractors/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/FKF/Dimensions/Interfaces/IFKDimensionsController/__init__.py +42 -0
- SymfWebAPI/WebAPI/Interface/FKF/Dimensions/Interfaces/IFKDimensionsController/_common.py +19 -0
- SymfWebAPI/WebAPI/Interface/FKF/Dimensions/Interfaces/IFKDimensionsController/_ops.py +20 -0
- SymfWebAPI/WebAPI/Interface/FKF/Dimensions/Interfaces/__init__.py +21 -0
- SymfWebAPI/WebAPI/Interface/FKF/Dimensions/__init__.py +21 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/Interfaces/IFKDocumentAttachmentsController/__init__.py +41 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/Interfaces/IFKDocumentAttachmentsController/_common.py +19 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/Interfaces/IFKDocumentAttachmentsController/_ops.py +14 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/Interfaces/IFKDocumentLinksController/__init__.py +41 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/Interfaces/IFKDocumentLinksController/_common.py +19 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/Interfaces/IFKDocumentLinksController/_ops.py +14 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/Interfaces/IFKDocumentsBusinessIssueController/__init__.py +70 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/Interfaces/IFKDocumentsBusinessIssueController/_common.py +27 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/Interfaces/IFKDocumentsBusinessIssueController/_ops.py +31 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/Interfaces/IFKDocumentsController/__init__.py +161 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/Interfaces/IFKDocumentsController/_common.py +91 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/Interfaces/IFKDocumentsController/_ops.py +75 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/Interfaces/IFKDocumentsIssueController/__init__.py +43 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/Interfaces/IFKDocumentsIssueController/_common.py +15 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/Interfaces/IFKDocumentsIssueController/_ops.py +21 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/Interfaces/__init__.py +25 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/ViewModels/Issue/Business/__init__.py +75 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/ViewModels/Issue/Custom/__init__.py +151 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/ViewModels/Issue/__init__.py +12 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/ViewModels/Rdf/__init__.py +13 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/ViewModels/Transactions/__init__.py +33 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/ViewModels/V2026_1/__init__.py +73 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/ViewModels/__init__.py +227 -0
- SymfWebAPI/WebAPI/Interface/FKF/Documents/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/FKF/Employees/Interfaces/IFKEmployeesController/__init__.py +99 -0
- SymfWebAPI/WebAPI/Interface/FKF/Employees/Interfaces/IFKEmployeesController/_common.py +45 -0
- SymfWebAPI/WebAPI/Interface/FKF/Employees/Interfaces/IFKEmployeesController/_ops.py +42 -0
- SymfWebAPI/WebAPI/Interface/FKF/Employees/Interfaces/__init__.py +21 -0
- SymfWebAPI/WebAPI/Interface/FKF/Employees/ViewModels/__init__.py +30 -0
- SymfWebAPI/WebAPI/Interface/FKF/Employees/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/FKF/__init__.py +27 -0
- SymfWebAPI/WebAPI/Interface/HMF/Develogic/Interfaces/IDevelogicPurchasesController/__init__.py +28 -0
- SymfWebAPI/WebAPI/Interface/HMF/Develogic/Interfaces/IDevelogicPurchasesController/_common.py +10 -0
- SymfWebAPI/WebAPI/Interface/HMF/Develogic/Interfaces/IDevelogicPurchasesController/_ops.py +13 -0
- SymfWebAPI/WebAPI/Interface/HMF/Develogic/Interfaces/IDevelogicSalesController/__init__.py +58 -0
- SymfWebAPI/WebAPI/Interface/HMF/Develogic/Interfaces/IDevelogicSalesController/_common.py +27 -0
- SymfWebAPI/WebAPI/Interface/HMF/Develogic/Interfaces/IDevelogicSalesController/_ops.py +27 -0
- SymfWebAPI/WebAPI/Interface/HMF/Develogic/Interfaces/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/HMF/Develogic/ViewModels/V2026_1/__init__.py +62 -0
- SymfWebAPI/WebAPI/Interface/HMF/Develogic/ViewModels/__init__.py +69 -0
- SymfWebAPI/WebAPI/Interface/HMF/Develogic/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/HMF/__init__.py +21 -0
- SymfWebAPI/WebAPI/Interface/Interfaces/ISessionController/__init__.py +34 -0
- SymfWebAPI/WebAPI/Interface/Interfaces/ISessionController/_common.py +10 -0
- SymfWebAPI/WebAPI/Interface/Interfaces/ISessionController/_ops.py +9 -0
- SymfWebAPI/WebAPI/Interface/Interfaces/__init__.py +21 -0
- SymfWebAPI/WebAPI/Interface/InventoryStates/Interfaces/IInventoryStatesController/__init__.py +98 -0
- SymfWebAPI/WebAPI/Interface/InventoryStates/Interfaces/IInventoryStatesController/_common.py +46 -0
- SymfWebAPI/WebAPI/Interface/InventoryStates/Interfaces/IInventoryStatesController/_ops.py +44 -0
- SymfWebAPI/WebAPI/Interface/InventoryStates/Interfaces/__init__.py +21 -0
- SymfWebAPI/WebAPI/Interface/InventoryStates/ViewModels/__init__.py +11 -0
- SymfWebAPI/WebAPI/Interface/InventoryStates/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/IOssContractorsController/__init__.py +55 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/IOssContractorsController/_common.py +24 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/IOssContractorsController/_ops.py +22 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/IOssOrderController/__init__.py +58 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/IOssOrderController/_common.py +25 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/IOssOrderController/_ops.py +28 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/IOssProductController/__init__.py +55 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/IOssProductController/_common.py +24 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/IOssProductController/_ops.py +24 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/IOssProductMapsController/__init__.py +84 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/IOssProductMapsController/_common.py +37 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/IOssProductMapsController/_ops.py +36 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/IOssReportsController/__init__.py +55 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/IOssReportsController/_common.py +24 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/IOssReportsController/_ops.py +24 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/IOssSaleController/__init__.py +58 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/IOssSaleController/_common.py +27 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/IOssSaleController/_ops.py +28 -0
- SymfWebAPI/WebAPI/Interface/OSS/Interfaces/__init__.py +26 -0
- SymfWebAPI/WebAPI/Interface/OSS/ViewModels/Common/__init__.py +35 -0
- SymfWebAPI/WebAPI/Interface/OSS/ViewModels/Orders/__init__.py +64 -0
- SymfWebAPI/WebAPI/Interface/OSS/ViewModels/Sales/V2026_1/__init__.py +43 -0
- SymfWebAPI/WebAPI/Interface/OSS/ViewModels/Sales/__init__.py +85 -0
- SymfWebAPI/WebAPI/Interface/OSS/ViewModels/__init__.py +38 -0
- SymfWebAPI/WebAPI/Interface/OSS/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/Orders/Interfaces/IOrderDimensions2Controller/__init__.py +70 -0
- SymfWebAPI/WebAPI/Interface/Orders/Interfaces/IOrderDimensions2Controller/_common.py +33 -0
- SymfWebAPI/WebAPI/Interface/Orders/Interfaces/IOrderDimensions2Controller/_ops.py +32 -0
- SymfWebAPI/WebAPI/Interface/Orders/Interfaces/IOrderDimensionsController/__init__.py +128 -0
- SymfWebAPI/WebAPI/Interface/Orders/Interfaces/IOrderDimensionsController/_common.py +63 -0
- SymfWebAPI/WebAPI/Interface/Orders/Interfaces/IOrderDimensionsController/_ops.py +52 -0
- SymfWebAPI/WebAPI/Interface/Orders/Interfaces/IOrdersController/__init__.py +236 -0
- SymfWebAPI/WebAPI/Interface/Orders/Interfaces/IOrdersController/_common.py +130 -0
- SymfWebAPI/WebAPI/Interface/Orders/Interfaces/IOrdersController/_ops.py +110 -0
- SymfWebAPI/WebAPI/Interface/Orders/Interfaces/IOrdersIssueController/__init__.py +115 -0
- SymfWebAPI/WebAPI/Interface/Orders/Interfaces/IOrdersIssueController/_common.py +55 -0
- SymfWebAPI/WebAPI/Interface/Orders/Interfaces/IOrdersIssueController/_ops.py +49 -0
- SymfWebAPI/WebAPI/Interface/Orders/Interfaces/__init__.py +24 -0
- SymfWebAPI/WebAPI/Interface/Orders/ViewModels/__init__.py +302 -0
- SymfWebAPI/WebAPI/Interface/Orders/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/OwnOrders/Interfaces/IOwnOrderDimensions2Controller/__init__.py +70 -0
- SymfWebAPI/WebAPI/Interface/OwnOrders/Interfaces/IOwnOrderDimensions2Controller/_common.py +33 -0
- SymfWebAPI/WebAPI/Interface/OwnOrders/Interfaces/IOwnOrderDimensions2Controller/_ops.py +32 -0
- SymfWebAPI/WebAPI/Interface/OwnOrders/Interfaces/IOwnOrderDimensionsController/__init__.py +128 -0
- SymfWebAPI/WebAPI/Interface/OwnOrders/Interfaces/IOwnOrderDimensionsController/_common.py +63 -0
- SymfWebAPI/WebAPI/Interface/OwnOrders/Interfaces/IOwnOrderDimensionsController/_ops.py +52 -0
- SymfWebAPI/WebAPI/Interface/OwnOrders/Interfaces/IOwnOrdersController/__init__.py +207 -0
- SymfWebAPI/WebAPI/Interface/OwnOrders/Interfaces/IOwnOrdersController/_common.py +115 -0
- SymfWebAPI/WebAPI/Interface/OwnOrders/Interfaces/IOwnOrdersController/_ops.py +97 -0
- SymfWebAPI/WebAPI/Interface/OwnOrders/Interfaces/IOwnOrdersIssueController/__init__.py +99 -0
- SymfWebAPI/WebAPI/Interface/OwnOrders/Interfaces/IOwnOrdersIssueController/_common.py +47 -0
- SymfWebAPI/WebAPI/Interface/OwnOrders/Interfaces/IOwnOrdersIssueController/_ops.py +39 -0
- SymfWebAPI/WebAPI/Interface/OwnOrders/Interfaces/__init__.py +24 -0
- SymfWebAPI/WebAPI/Interface/OwnOrders/ViewModels/__init__.py +205 -0
- SymfWebAPI/WebAPI/Interface/OwnOrders/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/Payments/Interfaces/IPaymentsController/__init__.py +189 -0
- SymfWebAPI/WebAPI/Interface/Payments/Interfaces/IPaymentsController/_common.py +104 -0
- SymfWebAPI/WebAPI/Interface/Payments/Interfaces/IPaymentsController/_ops.py +85 -0
- SymfWebAPI/WebAPI/Interface/Payments/Interfaces/ISettlementsController/__init__.py +114 -0
- SymfWebAPI/WebAPI/Interface/Payments/Interfaces/ISettlementsController/_common.py +69 -0
- SymfWebAPI/WebAPI/Interface/Payments/Interfaces/ISettlementsController/_ops.py +48 -0
- SymfWebAPI/WebAPI/Interface/Payments/Interfaces/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/Payments/ViewModels/Issue/__init__.py +38 -0
- SymfWebAPI/WebAPI/Interface/Payments/ViewModels/IssueKP/__init__.py +30 -0
- SymfWebAPI/WebAPI/Interface/Payments/ViewModels/__init__.py +124 -0
- SymfWebAPI/WebAPI/Interface/Payments/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/IPriceListsController/__init__.py +42 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/IPriceListsController/_common.py +16 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/IPriceListsController/_ops.py +20 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/IProductDimensions2Controller/__init__.py +27 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/IProductDimensions2Controller/_common.py +10 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/IProductDimensions2Controller/_ops.py +13 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/IProductDimensionsController/__init__.py +41 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/IProductDimensionsController/_common.py +19 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/IProductDimensionsController/_ops.py +17 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/IProductPhotosController/__init__.py +28 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/IProductPhotosController/_common.py +11 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/IProductPhotosController/_ops.py +13 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/IProductPricesController/__init__.py +178 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/IProductPricesController/_common.py +77 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/IProductPricesController/_ops.py +80 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/IProductsController/__init__.py +247 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/IProductsController/_common.py +113 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/IProductsController/_ops.py +109 -0
- SymfWebAPI/WebAPI/Interface/Products/Interfaces/__init__.py +26 -0
- SymfWebAPI/WebAPI/Interface/Products/ViewModels/PriceCalculations/__init__.py +91 -0
- SymfWebAPI/WebAPI/Interface/Products/ViewModels/PriceLists/__init__.py +60 -0
- SymfWebAPI/WebAPI/Interface/Products/ViewModels/Prices/__init__.py +128 -0
- SymfWebAPI/WebAPI/Interface/Products/ViewModels/__init__.py +217 -0
- SymfWebAPI/WebAPI/Interface/Products/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/Purchases/Interfaces/IPurchasesController/__init__.py +221 -0
- SymfWebAPI/WebAPI/Interface/Purchases/Interfaces/IPurchasesController/_common.py +124 -0
- SymfWebAPI/WebAPI/Interface/Purchases/Interfaces/IPurchasesController/_ops.py +103 -0
- SymfWebAPI/WebAPI/Interface/Purchases/Interfaces/IPurchasesDimensions2Controller/__init__.py +70 -0
- SymfWebAPI/WebAPI/Interface/Purchases/Interfaces/IPurchasesDimensions2Controller/_common.py +33 -0
- SymfWebAPI/WebAPI/Interface/Purchases/Interfaces/IPurchasesDimensions2Controller/_ops.py +32 -0
- SymfWebAPI/WebAPI/Interface/Purchases/Interfaces/IPurchasesDimensionsController/__init__.py +128 -0
- SymfWebAPI/WebAPI/Interface/Purchases/Interfaces/IPurchasesDimensionsController/_common.py +63 -0
- SymfWebAPI/WebAPI/Interface/Purchases/Interfaces/IPurchasesDimensionsController/_ops.py +52 -0
- SymfWebAPI/WebAPI/Interface/Purchases/Interfaces/IPurchasesIssueController/__init__.py +86 -0
- SymfWebAPI/WebAPI/Interface/Purchases/Interfaces/IPurchasesIssueController/_common.py +40 -0
- SymfWebAPI/WebAPI/Interface/Purchases/Interfaces/IPurchasesIssueController/_ops.py +38 -0
- SymfWebAPI/WebAPI/Interface/Purchases/Interfaces/__init__.py +24 -0
- SymfWebAPI/WebAPI/Interface/Purchases/ViewModels/V2026_1/__init__.py +171 -0
- SymfWebAPI/WebAPI/Interface/Purchases/ViewModels/__init__.py +245 -0
- SymfWebAPI/WebAPI/Interface/Purchases/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/RepX/Interfaces/IReportsController/__init__.py +28 -0
- SymfWebAPI/WebAPI/Interface/RepX/Interfaces/IReportsController/_common.py +11 -0
- SymfWebAPI/WebAPI/Interface/RepX/Interfaces/IReportsController/_ops.py +13 -0
- SymfWebAPI/WebAPI/Interface/RepX/Interfaces/__init__.py +21 -0
- SymfWebAPI/WebAPI/Interface/RepX/ViewModels/__init__.py +14 -0
- SymfWebAPI/WebAPI/Interface/RepX/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/Reservations/Interfaces/IReservationsController/__init__.py +114 -0
- SymfWebAPI/WebAPI/Interface/Reservations/Interfaces/IReservationsController/_common.py +50 -0
- SymfWebAPI/WebAPI/Interface/Reservations/Interfaces/IReservationsController/_ops.py +48 -0
- SymfWebAPI/WebAPI/Interface/Reservations/Interfaces/__init__.py +21 -0
- SymfWebAPI/WebAPI/Interface/Reservations/ViewModels/__init__.py +110 -0
- SymfWebAPI/WebAPI/Interface/Reservations/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/Sales/Interfaces/IFiscalPrinterController/__init__.py +27 -0
- SymfWebAPI/WebAPI/Interface/Sales/Interfaces/IFiscalPrinterController/_common.py +10 -0
- SymfWebAPI/WebAPI/Interface/Sales/Interfaces/IFiscalPrinterController/_ops.py +12 -0
- SymfWebAPI/WebAPI/Interface/Sales/Interfaces/ISalesController/__init__.py +237 -0
- SymfWebAPI/WebAPI/Interface/Sales/Interfaces/ISalesController/_common.py +130 -0
- SymfWebAPI/WebAPI/Interface/Sales/Interfaces/ISalesController/_ops.py +111 -0
- SymfWebAPI/WebAPI/Interface/Sales/Interfaces/ISalesDimensions2Controller/__init__.py +70 -0
- SymfWebAPI/WebAPI/Interface/Sales/Interfaces/ISalesDimensions2Controller/_common.py +33 -0
- SymfWebAPI/WebAPI/Interface/Sales/Interfaces/ISalesDimensions2Controller/_ops.py +32 -0
- SymfWebAPI/WebAPI/Interface/Sales/Interfaces/ISalesDimensionsController/__init__.py +128 -0
- SymfWebAPI/WebAPI/Interface/Sales/Interfaces/ISalesDimensionsController/_common.py +63 -0
- SymfWebAPI/WebAPI/Interface/Sales/Interfaces/ISalesDimensionsController/_ops.py +52 -0
- SymfWebAPI/WebAPI/Interface/Sales/Interfaces/ISalesIssueController/__init__.py +129 -0
- SymfWebAPI/WebAPI/Interface/Sales/Interfaces/ISalesIssueController/_common.py +63 -0
- SymfWebAPI/WebAPI/Interface/Sales/Interfaces/ISalesIssueController/_ops.py +53 -0
- SymfWebAPI/WebAPI/Interface/Sales/Interfaces/__init__.py +25 -0
- SymfWebAPI/WebAPI/Interface/Sales/ViewModels/CorrectionIssue/V2026_1/__init__.py +42 -0
- SymfWebAPI/WebAPI/Interface/Sales/ViewModels/CorrectionIssue/__init__.py +23 -0
- SymfWebAPI/WebAPI/Interface/Sales/ViewModels/DocumentIssue/__init__.py +11 -0
- SymfWebAPI/WebAPI/Interface/Sales/ViewModels/__init__.py +325 -0
- SymfWebAPI/WebAPI/Interface/Sales/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/ViewModels/__init__.py +16 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/IDeliveriesController/__init__.py +27 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/IDeliveriesController/_common.py +11 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/IDeliveriesController/_ops.py +13 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/IDeliveryDimensionsController/__init__.py +41 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/IDeliveryDimensionsController/_common.py +19 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/IDeliveryDimensionsController/_ops.py +17 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/IWarehouseDocumentDimensions2Controller/__init__.py +70 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/IWarehouseDocumentDimensions2Controller/_common.py +33 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/IWarehouseDocumentDimensions2Controller/_ops.py +32 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/IWarehouseDocumentDimensionsController/__init__.py +128 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/IWarehouseDocumentDimensionsController/_common.py +63 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/IWarehouseDocumentDimensionsController/_ops.py +52 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/IWarehouseDocumentsController/__init__.py +177 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/IWarehouseDocumentsController/_common.py +100 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/IWarehouseDocumentsController/_ops.py +83 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/IWarehouseDocumentsIssueController/__init__.py +85 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/IWarehouseDocumentsIssueController/_common.py +38 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/IWarehouseDocumentsIssueController/_ops.py +34 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/Interfaces/__init__.py +26 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/ViewModels/__init__.py +265 -0
- SymfWebAPI/WebAPI/Interface/Warehouse/__init__.py +22 -0
- SymfWebAPI/WebAPI/Interface/__init__.py +40 -0
- SymfWebAPI/WebAPI/__init__.py +21 -0
- SymfWebAPI/__init__.py +63 -0
- SymfWebAPI/client.py +129 -0
- SymfWebAPI/config.py +60 -0
- SymfWebAPI/enums.py +36 -0
- SymfWebAPI/errors.py +47 -0
- SymfWebAPI/executors.py +92 -0
- SymfWebAPI/operations.py +116 -0
- SymfWebAPI/protocols.py +85 -0
- SymfWebAPI/request_engine.py +43 -0
- SymfWebAPI/response.py +21 -0
- SymfWebAPI/runtime.py +85 -0
- SymfWebAPI/session.py +349 -0
- SymfWebAPI/transport/__init__.py +9 -0
- SymfWebAPI/transport/httpx_async.py +77 -0
- SymfWebAPI/transport/httpx_sync.py +78 -0
- symfwebapi-1.26.10.1.dist-info/METADATA +78 -0
- symfwebapi-1.26.10.1.dist-info/RECORD +329 -0
- symfwebapi-1.26.10.1.dist-info/WHEEL +5 -0
- symfwebapi-1.26.10.1.dist-info/licenses/LICENSE +29 -0
- symfwebapi-1.26.10.1.dist-info/top_level.txt +1 -0
SymfWebAPI/runtime.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""Fabryki klientów Sync/Async oparte na domyślnych transportach."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Awaitable, Callable, Optional, cast
|
|
6
|
+
|
|
7
|
+
from .client import AsyncAPI, SyncAPI
|
|
8
|
+
from .config import ClientConfig
|
|
9
|
+
from .protocols import AsyncTransportProtocol, SyncTransportProtocol
|
|
10
|
+
from .session import SessionManager, SessionState
|
|
11
|
+
from .transport import AsyncHttpxTransport, SyncHttpxTransport
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def build_sync_client(
|
|
15
|
+
config: ClientConfig,
|
|
16
|
+
*,
|
|
17
|
+
transport: SyncTransportProtocol | None = None,
|
|
18
|
+
manage_transport: bool | None = None,
|
|
19
|
+
on_session_open: Optional[Callable[[SessionState], None]] = None,
|
|
20
|
+
on_session_close: Optional[Callable[[SessionState], None]] = None,
|
|
21
|
+
on_session_invalidate: Optional[Callable[[SessionState], None]] = None,
|
|
22
|
+
) -> SyncAPI:
|
|
23
|
+
"""Tworzy w pełni skonfigurowanego SyncAPI."""
|
|
24
|
+
|
|
25
|
+
own_transport = False
|
|
26
|
+
if transport is None:
|
|
27
|
+
transport = SyncHttpxTransport(config)
|
|
28
|
+
own_transport = True
|
|
29
|
+
if manage_transport is not None:
|
|
30
|
+
own_transport = manage_transport
|
|
31
|
+
|
|
32
|
+
session_manager = SessionManager(
|
|
33
|
+
config,
|
|
34
|
+
backend=transport,
|
|
35
|
+
on_open=on_session_open,
|
|
36
|
+
on_close=on_session_close,
|
|
37
|
+
on_invalidate=on_session_invalidate,
|
|
38
|
+
)
|
|
39
|
+
shutdown_hook: Optional[Callable[[], None]] = None
|
|
40
|
+
if own_transport and hasattr(transport, "close"):
|
|
41
|
+
shutdown_hook = cast(Callable[[], None], getattr(transport, "close"))
|
|
42
|
+
|
|
43
|
+
return SyncAPI(
|
|
44
|
+
config,
|
|
45
|
+
session_manager=session_manager,
|
|
46
|
+
request_fn=transport.request,
|
|
47
|
+
shutdown_hook=shutdown_hook,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def build_async_client(
|
|
52
|
+
config: ClientConfig,
|
|
53
|
+
*,
|
|
54
|
+
transport: AsyncTransportProtocol | None = None,
|
|
55
|
+
manage_transport: bool | None = None,
|
|
56
|
+
on_session_open: Optional[Callable[[SessionState], None]] = None,
|
|
57
|
+
on_session_close: Optional[Callable[[SessionState], None]] = None,
|
|
58
|
+
on_session_invalidate: Optional[Callable[[SessionState], None]] = None,
|
|
59
|
+
) -> AsyncAPI:
|
|
60
|
+
"""Tworzy AsyncAPI gotowe do użycia."""
|
|
61
|
+
|
|
62
|
+
own_transport = False
|
|
63
|
+
if transport is None:
|
|
64
|
+
transport = AsyncHttpxTransport(config)
|
|
65
|
+
own_transport = True
|
|
66
|
+
if manage_transport is not None:
|
|
67
|
+
own_transport = manage_transport
|
|
68
|
+
|
|
69
|
+
session_manager = SessionManager(
|
|
70
|
+
config,
|
|
71
|
+
backend=transport,
|
|
72
|
+
on_open=on_session_open,
|
|
73
|
+
on_close=on_session_close,
|
|
74
|
+
on_invalidate=on_session_invalidate,
|
|
75
|
+
)
|
|
76
|
+
shutdown_hook: Optional[Callable[[], Awaitable[None]]] = None
|
|
77
|
+
if own_transport and hasattr(transport, "aclose"):
|
|
78
|
+
shutdown_hook = cast(Callable[[], Awaitable[None]], getattr(transport, "aclose"))
|
|
79
|
+
|
|
80
|
+
return AsyncAPI(
|
|
81
|
+
config,
|
|
82
|
+
session_manager=session_manager,
|
|
83
|
+
request_fn=transport.request,
|
|
84
|
+
shutdown_hook=shutdown_hook,
|
|
85
|
+
)
|
SymfWebAPI/session.py
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
"""Zarządzanie sesją WebAPI (handshake, odświeżanie, zamykanie)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from datetime import datetime, timedelta, timezone
|
|
8
|
+
import logging
|
|
9
|
+
import threading
|
|
10
|
+
from typing import Optional, Protocol, Callable, Any
|
|
11
|
+
|
|
12
|
+
from .config import ClientConfig
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class SessionBackend(Protocol):
|
|
16
|
+
"""Minimalny interfejs backendu wykonującego żądania sesyjne."""
|
|
17
|
+
|
|
18
|
+
async def open_async(self, device_name: str) -> str:
|
|
19
|
+
"""Zwraca nowy token sesyjny."""
|
|
20
|
+
|
|
21
|
+
def open_sync(self, device_name: str) -> str:
|
|
22
|
+
"""Wariant synchroniczny."""
|
|
23
|
+
|
|
24
|
+
async def close_async(self, token: str) -> None:
|
|
25
|
+
"""Zamyka wskazaną sesję."""
|
|
26
|
+
|
|
27
|
+
def close_sync(self, token: str) -> None:
|
|
28
|
+
"""Wariant synchroniczny."""
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass(slots=True)
|
|
32
|
+
class SessionState:
|
|
33
|
+
token: Optional[str] = None
|
|
34
|
+
opened_at: Optional[datetime] = None
|
|
35
|
+
expires_at: Optional[datetime] = None
|
|
36
|
+
|
|
37
|
+
def is_expired(self, *, max_age: Optional[timedelta], now: Optional[datetime] = None) -> bool:
|
|
38
|
+
if not self.token:
|
|
39
|
+
return True
|
|
40
|
+
now = now or datetime.now(timezone.utc)
|
|
41
|
+
if self.expires_at and now >= self.expires_at:
|
|
42
|
+
return True
|
|
43
|
+
if max_age and self.opened_at:
|
|
44
|
+
return now - self.opened_at >= max_age
|
|
45
|
+
return False
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class _SharedSessionState:
|
|
49
|
+
"""Thread-safe shared state used by sync/async session managers."""
|
|
50
|
+
|
|
51
|
+
def __init__(self, config: ClientConfig) -> None:
|
|
52
|
+
self._config = config
|
|
53
|
+
self.state = SessionState()
|
|
54
|
+
self.lock = threading.RLock()
|
|
55
|
+
self.condition = threading.Condition(self.lock)
|
|
56
|
+
self.refreshing = False
|
|
57
|
+
self._async_waiters: list[tuple[Any, Any]] = []
|
|
58
|
+
|
|
59
|
+
def is_fresh(self) -> bool:
|
|
60
|
+
return not self.state.is_expired(max_age=self._config.max_session_age)
|
|
61
|
+
|
|
62
|
+
def wait_for_refresh_locked(self) -> None:
|
|
63
|
+
while self.refreshing:
|
|
64
|
+
self.condition.wait()
|
|
65
|
+
|
|
66
|
+
async def wait_for_refresh_async(self) -> None:
|
|
67
|
+
loop = asyncio.get_running_loop()
|
|
68
|
+
with self.lock:
|
|
69
|
+
if not self.refreshing:
|
|
70
|
+
return
|
|
71
|
+
future = loop.create_future()
|
|
72
|
+
self._async_waiters.append((loop, future))
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
await future
|
|
76
|
+
finally:
|
|
77
|
+
with self.lock:
|
|
78
|
+
self._async_waiters = [
|
|
79
|
+
(registered_loop, registered_future)
|
|
80
|
+
for registered_loop, registered_future in self._async_waiters
|
|
81
|
+
if registered_future is not future
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
def _notify_async_waiters_locked(self) -> None:
|
|
85
|
+
for loop, future in self._async_waiters:
|
|
86
|
+
if future.done():
|
|
87
|
+
continue
|
|
88
|
+
try:
|
|
89
|
+
loop.call_soon_threadsafe(future.set_result, None)
|
|
90
|
+
except RuntimeError:
|
|
91
|
+
continue
|
|
92
|
+
self._async_waiters.clear()
|
|
93
|
+
|
|
94
|
+
def fail_refresh(self) -> None:
|
|
95
|
+
with self.lock:
|
|
96
|
+
self.refreshing = False
|
|
97
|
+
self.condition.notify_all()
|
|
98
|
+
self._notify_async_waiters_locked()
|
|
99
|
+
|
|
100
|
+
def commit_refresh(self, token: str) -> SessionState:
|
|
101
|
+
now = datetime.now(timezone.utc)
|
|
102
|
+
expires_at = now + self._config.max_session_age if self._config.max_session_age else None
|
|
103
|
+
new_state = SessionState(token=token, opened_at=now, expires_at=expires_at)
|
|
104
|
+
with self.lock:
|
|
105
|
+
self.state = new_state
|
|
106
|
+
self.refreshing = False
|
|
107
|
+
self.condition.notify_all()
|
|
108
|
+
self._notify_async_waiters_locked()
|
|
109
|
+
return self.state
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class SyncSessionManager:
|
|
113
|
+
"""Synchronous session lifecycle coordinator."""
|
|
114
|
+
|
|
115
|
+
def __init__(
|
|
116
|
+
self,
|
|
117
|
+
config: ClientConfig,
|
|
118
|
+
backend: SessionBackend,
|
|
119
|
+
shared_state: Optional[_SharedSessionState] = None,
|
|
120
|
+
*,
|
|
121
|
+
logger: logging.Logger,
|
|
122
|
+
on_open: Optional[Callable[[SessionState], None]] = None,
|
|
123
|
+
on_close: Optional[Callable[[SessionState], None]] = None,
|
|
124
|
+
on_invalidate: Optional[Callable[[SessionState], None]] = None,
|
|
125
|
+
) -> None:
|
|
126
|
+
self._config = config
|
|
127
|
+
self._backend = backend
|
|
128
|
+
self._shared = shared_state or _SharedSessionState(config)
|
|
129
|
+
self._logger = logger
|
|
130
|
+
self._on_open = on_open
|
|
131
|
+
self._on_close = on_close
|
|
132
|
+
self._on_invalidate = on_invalidate
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def state(self) -> SessionState:
|
|
136
|
+
return self._shared.state
|
|
137
|
+
|
|
138
|
+
def _close_previous_sync(self, previous_state: SessionState) -> None:
|
|
139
|
+
token = previous_state.token
|
|
140
|
+
if not token:
|
|
141
|
+
return
|
|
142
|
+
try:
|
|
143
|
+
self._backend.close_sync(token)
|
|
144
|
+
self._logger.info("Closed previous sync session for device=%s", self._config.device_name)
|
|
145
|
+
if self._on_close:
|
|
146
|
+
self._on_close(previous_state)
|
|
147
|
+
except Exception:
|
|
148
|
+
self._logger.warning(
|
|
149
|
+
"Failed to close previous sync session for device=%s",
|
|
150
|
+
self._config.device_name,
|
|
151
|
+
exc_info=True,
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
def ensure_sync(self) -> SessionState:
|
|
155
|
+
while True:
|
|
156
|
+
with self._shared.lock:
|
|
157
|
+
if self._shared.is_fresh():
|
|
158
|
+
return self._shared.state
|
|
159
|
+
if self._shared.refreshing:
|
|
160
|
+
self._shared.wait_for_refresh_locked()
|
|
161
|
+
continue
|
|
162
|
+
self._shared.refreshing = True
|
|
163
|
+
previous_state = self._shared.state
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
self._close_previous_sync(previous_state)
|
|
167
|
+
token = self._backend.open_sync(self._config.device_name)
|
|
168
|
+
except Exception:
|
|
169
|
+
self._shared.fail_refresh()
|
|
170
|
+
raise
|
|
171
|
+
|
|
172
|
+
new_state = self._shared.commit_refresh(token)
|
|
173
|
+
self._logger.info("Opened sync session for device=%s", self._config.device_name)
|
|
174
|
+
if self._on_open:
|
|
175
|
+
self._on_open(new_state)
|
|
176
|
+
return new_state
|
|
177
|
+
|
|
178
|
+
def close_sync(self) -> None:
|
|
179
|
+
with self._shared.lock:
|
|
180
|
+
self._shared.wait_for_refresh_locked()
|
|
181
|
+
if not self._shared.state.token:
|
|
182
|
+
return
|
|
183
|
+
token = self._shared.state.token
|
|
184
|
+
prev_state = self._shared.state
|
|
185
|
+
self._shared.state = SessionState()
|
|
186
|
+
self._shared.condition.notify_all()
|
|
187
|
+
|
|
188
|
+
try:
|
|
189
|
+
self._backend.close_sync(token)
|
|
190
|
+
self._logger.info("Closed sync session for device=%s", self._config.device_name)
|
|
191
|
+
finally:
|
|
192
|
+
if self._on_close:
|
|
193
|
+
self._on_close(prev_state)
|
|
194
|
+
|
|
195
|
+
def invalidate(self) -> None:
|
|
196
|
+
with self._shared.lock:
|
|
197
|
+
self._shared.wait_for_refresh_locked()
|
|
198
|
+
if self._shared.state.token:
|
|
199
|
+
self._logger.info("Invalidated session for device=%s", self._config.device_name)
|
|
200
|
+
if self._on_invalidate:
|
|
201
|
+
self._on_invalidate(self._shared.state)
|
|
202
|
+
self._shared.state = SessionState()
|
|
203
|
+
self._shared.condition.notify_all()
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
class AsyncSessionManager:
|
|
207
|
+
"""Asynchronous session lifecycle coordinator."""
|
|
208
|
+
|
|
209
|
+
def __init__(
|
|
210
|
+
self,
|
|
211
|
+
config: ClientConfig,
|
|
212
|
+
backend: SessionBackend,
|
|
213
|
+
shared_state: Optional[_SharedSessionState] = None,
|
|
214
|
+
*,
|
|
215
|
+
logger: logging.Logger,
|
|
216
|
+
on_open: Optional[Callable[[SessionState], None]] = None,
|
|
217
|
+
on_close: Optional[Callable[[SessionState], None]] = None,
|
|
218
|
+
) -> None:
|
|
219
|
+
self._config = config
|
|
220
|
+
self._backend = backend
|
|
221
|
+
self._shared = shared_state or _SharedSessionState(config)
|
|
222
|
+
self._logger = logger
|
|
223
|
+
self._on_open = on_open
|
|
224
|
+
self._on_close = on_close
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def state(self) -> SessionState:
|
|
228
|
+
return self._shared.state
|
|
229
|
+
|
|
230
|
+
async def _close_previous_async(self, previous_state: SessionState) -> None:
|
|
231
|
+
token = previous_state.token
|
|
232
|
+
if not token:
|
|
233
|
+
return
|
|
234
|
+
try:
|
|
235
|
+
await self._backend.close_async(token)
|
|
236
|
+
self._logger.info("Closed previous async session for device=%s", self._config.device_name)
|
|
237
|
+
if self._on_close:
|
|
238
|
+
self._on_close(previous_state)
|
|
239
|
+
except Exception:
|
|
240
|
+
self._logger.warning(
|
|
241
|
+
"Failed to close previous async session for device=%s",
|
|
242
|
+
self._config.device_name,
|
|
243
|
+
exc_info=True,
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
async def ensure_async(self) -> SessionState:
|
|
247
|
+
while True:
|
|
248
|
+
# Hot path: in steady state most async calls only need to read
|
|
249
|
+
# the current token and skip lock/condition coordination.
|
|
250
|
+
current = self._shared.state
|
|
251
|
+
if not current.is_expired(max_age=self._config.max_session_age):
|
|
252
|
+
return current
|
|
253
|
+
|
|
254
|
+
with self._shared.lock:
|
|
255
|
+
if self._shared.is_fresh():
|
|
256
|
+
return self._shared.state
|
|
257
|
+
if self._shared.refreshing:
|
|
258
|
+
should_refresh = False
|
|
259
|
+
else:
|
|
260
|
+
self._shared.refreshing = True
|
|
261
|
+
previous_state = self._shared.state
|
|
262
|
+
should_refresh = True
|
|
263
|
+
|
|
264
|
+
if not should_refresh:
|
|
265
|
+
await self._shared.wait_for_refresh_async()
|
|
266
|
+
continue
|
|
267
|
+
|
|
268
|
+
try:
|
|
269
|
+
await self._close_previous_async(previous_state)
|
|
270
|
+
token = await self._backend.open_async(self._config.device_name)
|
|
271
|
+
except Exception:
|
|
272
|
+
self._shared.fail_refresh()
|
|
273
|
+
raise
|
|
274
|
+
|
|
275
|
+
new_state = self._shared.commit_refresh(token)
|
|
276
|
+
self._logger.info("Opened async session for device=%s", self._config.device_name)
|
|
277
|
+
if self._on_open:
|
|
278
|
+
self._on_open(new_state)
|
|
279
|
+
return new_state
|
|
280
|
+
|
|
281
|
+
async def close_async(self) -> None:
|
|
282
|
+
await self._shared.wait_for_refresh_async()
|
|
283
|
+
with self._shared.lock:
|
|
284
|
+
if not self._shared.state.token:
|
|
285
|
+
return
|
|
286
|
+
token = self._shared.state.token
|
|
287
|
+
prev_state = self._shared.state
|
|
288
|
+
self._shared.state = SessionState()
|
|
289
|
+
self._shared.condition.notify_all()
|
|
290
|
+
|
|
291
|
+
try:
|
|
292
|
+
await self._backend.close_async(token)
|
|
293
|
+
self._logger.info("Closed async session for device=%s", self._config.device_name)
|
|
294
|
+
finally:
|
|
295
|
+
if self._on_close:
|
|
296
|
+
self._on_close(prev_state)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
class SessionManager:
|
|
300
|
+
"""Backward-compatible facade coordinating sync and async session managers."""
|
|
301
|
+
|
|
302
|
+
def __init__(
|
|
303
|
+
self,
|
|
304
|
+
config: ClientConfig,
|
|
305
|
+
backend: SessionBackend,
|
|
306
|
+
*,
|
|
307
|
+
on_open: Optional[Callable[[SessionState], None]] = None,
|
|
308
|
+
on_close: Optional[Callable[[SessionState], None]] = None,
|
|
309
|
+
on_invalidate: Optional[Callable[[SessionState], None]] = None,
|
|
310
|
+
):
|
|
311
|
+
logger = logging.getLogger(__name__)
|
|
312
|
+
shared_state = _SharedSessionState(config)
|
|
313
|
+
self._sync = SyncSessionManager(
|
|
314
|
+
config,
|
|
315
|
+
backend,
|
|
316
|
+
shared_state,
|
|
317
|
+
logger=logger,
|
|
318
|
+
on_open=on_open,
|
|
319
|
+
on_close=on_close,
|
|
320
|
+
on_invalidate=on_invalidate,
|
|
321
|
+
)
|
|
322
|
+
self._async = AsyncSessionManager(
|
|
323
|
+
config,
|
|
324
|
+
backend,
|
|
325
|
+
shared_state,
|
|
326
|
+
logger=logger,
|
|
327
|
+
on_open=on_open,
|
|
328
|
+
on_close=on_close,
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
@property
|
|
332
|
+
def state(self) -> SessionState:
|
|
333
|
+
return self._sync.state
|
|
334
|
+
|
|
335
|
+
async def ensure_async(self) -> SessionState:
|
|
336
|
+
return await self._async.ensure_async()
|
|
337
|
+
|
|
338
|
+
def ensure_sync(self) -> SessionState:
|
|
339
|
+
return self._sync.ensure_sync()
|
|
340
|
+
|
|
341
|
+
async def close_async(self) -> None:
|
|
342
|
+
await self._async.close_async()
|
|
343
|
+
|
|
344
|
+
def close_sync(self) -> None:
|
|
345
|
+
self._sync.close_sync()
|
|
346
|
+
|
|
347
|
+
def invalidate(self) -> None:
|
|
348
|
+
"""Czyści lokalny token – użytkownik może wywołać po błędzie 401."""
|
|
349
|
+
self._sync.invalidate()
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Async HTTP transport using httpx."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, Optional
|
|
6
|
+
|
|
7
|
+
import httpx
|
|
8
|
+
|
|
9
|
+
from ..config import ClientConfig
|
|
10
|
+
from ..errors import TransportError
|
|
11
|
+
from ..session import SessionBackend
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AsyncHttpxTransport(SessionBackend):
|
|
15
|
+
def __init__(self, config: ClientConfig, *, client: httpx.AsyncClient | None = None) -> None:
|
|
16
|
+
self._config = config
|
|
17
|
+
self._client = client or httpx.AsyncClient(
|
|
18
|
+
base_url=config.base_url,
|
|
19
|
+
timeout=config.request_timeout,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
async def open_async(self, device_name: str) -> str:
|
|
23
|
+
path = "/api/Sessions/OpenNewSession"
|
|
24
|
+
try:
|
|
25
|
+
response = await self._client.get(
|
|
26
|
+
path,
|
|
27
|
+
params={"deviceName": device_name},
|
|
28
|
+
headers={"Authorization": f"Application {self._config.application_key}"},
|
|
29
|
+
)
|
|
30
|
+
response.raise_for_status()
|
|
31
|
+
return response.text.strip('"')
|
|
32
|
+
except httpx.HTTPError as exc:
|
|
33
|
+
raise TransportError(f"open session failed: {exc}", endpoint=path) from exc
|
|
34
|
+
|
|
35
|
+
def open_sync(self, device_name: str) -> str: # pragma: no cover - async backend
|
|
36
|
+
raise NotImplementedError("Użyj SyncHttpxTransport dla trybu sync")
|
|
37
|
+
|
|
38
|
+
async def close_async(self, token: str) -> None:
|
|
39
|
+
path = "/api/Sessions/CloseSession"
|
|
40
|
+
try:
|
|
41
|
+
response = await self._client.get(
|
|
42
|
+
path,
|
|
43
|
+
headers={"Authorization": f"Session {token}"},
|
|
44
|
+
)
|
|
45
|
+
response.raise_for_status()
|
|
46
|
+
except httpx.HTTPError as exc:
|
|
47
|
+
raise TransportError(f"close session failed: {exc}", endpoint=path) from exc
|
|
48
|
+
|
|
49
|
+
def close_sync(self, token: str) -> None: # pragma: no cover - async backend
|
|
50
|
+
raise NotImplementedError("Użyj SyncHttpxTransport dla trybu sync")
|
|
51
|
+
|
|
52
|
+
async def request(
|
|
53
|
+
self,
|
|
54
|
+
method: str,
|
|
55
|
+
path: str,
|
|
56
|
+
*,
|
|
57
|
+
token: str,
|
|
58
|
+
params: Optional[Dict[str, Any]] = None,
|
|
59
|
+
data: Any = None,
|
|
60
|
+
) -> httpx.Response:
|
|
61
|
+
headers = {"Authorization": f"Session {token}"}
|
|
62
|
+
request_kwargs: Dict[str, Any] = {"params": params, "headers": headers}
|
|
63
|
+
if data is not None:
|
|
64
|
+
if isinstance(data, (str, bytes, bytearray, memoryview)):
|
|
65
|
+
request_kwargs["content"] = data
|
|
66
|
+
if isinstance(data, str):
|
|
67
|
+
headers["Content-Type"] = "application/json"
|
|
68
|
+
else:
|
|
69
|
+
request_kwargs["json"] = data
|
|
70
|
+
try:
|
|
71
|
+
response = await self._client.request(method, path, **request_kwargs)
|
|
72
|
+
return response
|
|
73
|
+
except httpx.HTTPError as exc:
|
|
74
|
+
raise TransportError(f"request failed: {exc}", endpoint=path) from exc
|
|
75
|
+
|
|
76
|
+
async def aclose(self) -> None:
|
|
77
|
+
await self._client.aclose()
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Synchronous HTTP transport oparty o httpx.Client."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, Optional
|
|
6
|
+
|
|
7
|
+
import httpx
|
|
8
|
+
|
|
9
|
+
from ..config import ClientConfig
|
|
10
|
+
from ..errors import TransportError
|
|
11
|
+
from ..session import SessionBackend
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SyncHttpxTransport(SessionBackend):
|
|
15
|
+
"""Backend dla SyncAPI bazujący na httpx.Client."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, config: ClientConfig, *, client: httpx.Client | None = None) -> None:
|
|
18
|
+
self._config = config
|
|
19
|
+
self._client = client or httpx.Client(
|
|
20
|
+
base_url=config.base_url,
|
|
21
|
+
timeout=config.request_timeout,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
async def open_async(self, device_name: str) -> str: # pragma: no cover - sync backend
|
|
25
|
+
raise NotImplementedError("Użyj AsyncHttpxTransport dla trybu async")
|
|
26
|
+
|
|
27
|
+
def open_sync(self, device_name: str) -> str:
|
|
28
|
+
path = "/api/Sessions/OpenNewSession"
|
|
29
|
+
try:
|
|
30
|
+
response = self._client.get(
|
|
31
|
+
path,
|
|
32
|
+
params={"deviceName": device_name},
|
|
33
|
+
headers={"Authorization": f"Application {self._config.application_key}"},
|
|
34
|
+
)
|
|
35
|
+
response.raise_for_status()
|
|
36
|
+
return response.text.strip('"')
|
|
37
|
+
except httpx.HTTPError as exc:
|
|
38
|
+
raise TransportError(f"open session failed: {exc}", endpoint=path) from exc
|
|
39
|
+
|
|
40
|
+
async def close_async(self, token: str) -> None: # pragma: no cover - sync backend
|
|
41
|
+
raise NotImplementedError("Użyj AsyncHttpxTransport dla trybu async")
|
|
42
|
+
|
|
43
|
+
def close_sync(self, token: str) -> None:
|
|
44
|
+
path = "/api/Sessions/CloseSession"
|
|
45
|
+
try:
|
|
46
|
+
response = self._client.get(
|
|
47
|
+
path,
|
|
48
|
+
headers={"Authorization": f"Session {token}"},
|
|
49
|
+
)
|
|
50
|
+
response.raise_for_status()
|
|
51
|
+
except httpx.HTTPError as exc:
|
|
52
|
+
raise TransportError(f"close session failed: {exc}", endpoint=path) from exc
|
|
53
|
+
|
|
54
|
+
def request(
|
|
55
|
+
self,
|
|
56
|
+
method: str,
|
|
57
|
+
path: str,
|
|
58
|
+
*,
|
|
59
|
+
token: str,
|
|
60
|
+
params: Optional[Dict[str, Any]] = None,
|
|
61
|
+
data: Any = None,
|
|
62
|
+
) -> httpx.Response:
|
|
63
|
+
headers = {"Authorization": f"Session {token}"}
|
|
64
|
+
request_kwargs: Dict[str, Any] = {"params": params, "headers": headers}
|
|
65
|
+
if data is not None:
|
|
66
|
+
if isinstance(data, (str, bytes, bytearray, memoryview)):
|
|
67
|
+
request_kwargs["content"] = data
|
|
68
|
+
if isinstance(data, str):
|
|
69
|
+
headers["Content-Type"] = "application/json"
|
|
70
|
+
else:
|
|
71
|
+
request_kwargs["json"] = data
|
|
72
|
+
try:
|
|
73
|
+
return self._client.request(method, path, **request_kwargs)
|
|
74
|
+
except httpx.HTTPError as exc:
|
|
75
|
+
raise TransportError(f"request failed: {exc}", endpoint=path) from exc
|
|
76
|
+
|
|
77
|
+
def close(self) -> None:
|
|
78
|
+
self._client.close()
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: SymfWebAPI
|
|
3
|
+
Version: 1.26.10.1
|
|
4
|
+
Summary: Python client for Symfonia WebAPI (sync + async).
|
|
5
|
+
Author: Maciej Pondo
|
|
6
|
+
Maintainer: Maciej Pondo
|
|
7
|
+
License-Expression: BSD-3-Clause
|
|
8
|
+
Project-URL: Homepage, https://github.com/maku2903/symf-webapi-py
|
|
9
|
+
Project-URL: Repository, https://github.com/maku2903/symf-webapi-py
|
|
10
|
+
Requires-Python: >=3.11
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: httpx<0.29,>=0.27
|
|
14
|
+
Requires-Dist: pydantic<3.0,>=2.6
|
|
15
|
+
Provides-Extra: dev
|
|
16
|
+
Requires-Dist: pytest<9.0,>=8.0; extra == "dev"
|
|
17
|
+
Requires-Dist: ruff<0.5,>=0.3.0; extra == "dev"
|
|
18
|
+
Requires-Dist: build<2.0,>=1.2; extra == "dev"
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# SymfWebAPI
|
|
22
|
+
|
|
23
|
+
[](https://github.com/maku2903/symf-webapi-py/actions/workflows/public-ci-release.yml)
|
|
24
|
+
[](https://pypi.org/project/SymfWebAPI/)
|
|
25
|
+
[](https://pypi.org/project/SymfWebAPI/)
|
|
26
|
+
[](https://github.com/maku2903/symf-webapi-py/blob/main/LICENSE)
|
|
27
|
+
|
|
28
|
+
Pythonowa biblioteka kliencka do Symfonia WebAPI (sync + async) z typowanymi modelami i wygenerowanymi kontrolerami.
|
|
29
|
+
|
|
30
|
+
## Instalacja
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install SymfWebAPI
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Szybki start
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from SymfWebAPI import ClientConfig, WebAPI, build_async_client
|
|
40
|
+
|
|
41
|
+
config = ClientConfig(
|
|
42
|
+
domain="host:9000",
|
|
43
|
+
application_key="00000000-0000-0000-0000-000000000000",
|
|
44
|
+
device_name="integration-client",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
async with build_async_client(config) as api:
|
|
48
|
+
resp = await WebAPI.Interface.Products.Interfaces.IProductsController.Get(api, salePrices=False)
|
|
49
|
+
products = resp.unwrap()
|
|
50
|
+
print(len(products))
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Dokumentacja
|
|
54
|
+
|
|
55
|
+
- Omówienie biblioteki: `docs/overview.md`
|
|
56
|
+
- Przykłady: `examples/`
|
|
57
|
+
|
|
58
|
+
## Benchmark bez sekretów
|
|
59
|
+
|
|
60
|
+
Przykład benchmarku znajduje się w:
|
|
61
|
+
- `examples/benchmark_order_details.py`
|
|
62
|
+
|
|
63
|
+
Konfiguracja przez zmienne środowiskowe (brak hardcode klucza):
|
|
64
|
+
- `SYMFWEBAPI_DOMAIN`
|
|
65
|
+
- `SYMFWEBAPI_APP_KEY`
|
|
66
|
+
- `SYMFWEBAPI_DEVICE_NAME` (opcjonalnie)
|
|
67
|
+
- `SYMFWEBAPI_HTTPS` (opcjonalnie, np. `true`/`false`)
|
|
68
|
+
|
|
69
|
+
## Wersjonowanie
|
|
70
|
+
|
|
71
|
+
Wersja paczki ma format `X.WM.Wm.I`, np. `1.26.10.3`:
|
|
72
|
+
- `X` - major SDK,
|
|
73
|
+
- `WM.Wm` - docelowa wersja Symfonia WebAPI,
|
|
74
|
+
- `I` - iteracja SDK dla tej samej wersji WebAPI.
|
|
75
|
+
|
|
76
|
+
## Licencja
|
|
77
|
+
|
|
78
|
+
BSD-3-Clause.
|