@ -0,0 +1,53 @@ |
|||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
|||
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html |
|||
:alt: License: AGPL-3 |
|||
|
|||
Amazon Forecast Integration |
|||
================ |
|||
Manage your stock using the forecast report generated based on historical |
|||
time series data |
|||
|
|||
Installation |
|||
------------ |
|||
- www.odoo.com/documentation/16.0/setup/install.html |
|||
- Install our custom addon |
|||
|
|||
Configuration |
|||
------------- |
|||
* Add the parameter limit_time_real in the conf file with value equal to 7200 |
|||
|
|||
Company |
|||
------- |
|||
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ |
|||
|
|||
License |
|||
------- |
|||
Affero General Public License v3.0 (AGPL v3) |
|||
(https://www.gnu.org/licenses/agpl-3.0-standalone.html) |
|||
|
|||
Credits |
|||
------- |
|||
Developer : (V16) Shafna K @ Cybrosys, Contact: odoo@cybrosys.com |
|||
|
|||
Contacts |
|||
-------- |
|||
* Mail Contact : odoo@cybrosys.com |
|||
* Website : https://cybrosys.com |
|||
|
|||
Bug Tracker |
|||
----------- |
|||
Bugs are tracked on GitHub Issues. In case of trouble, please check there |
|||
if your issue has already been reported. |
|||
|
|||
Maintainer |
|||
---------- |
|||
.. image:: https://cybrosys.com/images/logo.png |
|||
:target: https://cybrosys.com |
|||
|
|||
This module is maintained by Cybrosys Technologies. |
|||
|
|||
For support and more information, please visit `Our Website <https://cybrosys.com/>`__ |
|||
|
|||
Further information |
|||
------------------- |
|||
HTML Description: `<static/description/index.html>`__ |
@ -0,0 +1,22 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Shafna K(odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from . import models |
@ -0,0 +1,60 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Shafna K(odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
{ |
|||
'name': "Amazon Forecast Integration", |
|||
'version': '16.0.1.0.0', |
|||
'category': 'Warehouse', |
|||
'summary': 'To predict the stock demand.', |
|||
'description': """ |
|||
This module helps to predict the demand and maintain right level of |
|||
inventory. |
|||
""", |
|||
'sequence': 20, |
|||
'author': " Cybrosys Techno Solutions", |
|||
'company': 'Cybrosys Techno Solutions', |
|||
'website': 'https://www.cybrosys.com', |
|||
'maintainer': 'Cybrosys Techno Solutions', |
|||
'support': 'Cybrosys Techno Solutions', |
|||
'depends': ['base', 'stock'], |
|||
'data': [ |
|||
'security/ir.model.access.csv', |
|||
'views/res_config_settings_views.xml', |
|||
'views/amazon_dataset_views.xml', |
|||
'views/amazon_fetch_data_views.xml', |
|||
'views/amazon_bucket_views.xml', |
|||
'views/menus.xml' |
|||
], |
|||
'assets': { |
|||
'web.assets_backend': [ |
|||
'https://cdn.jsdelivr.net/npm/chart.js', |
|||
'https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@3.0.0/dist/chartjs-adapter-date-fns.bundle.min.js', |
|||
'amazon_forecast_integration/static/src/js/graphView.js', |
|||
'amazon_forecast_integration/static/src/xml/graph_view.xml', |
|||
] |
|||
}, |
|||
'external_dependencies': {'python': ['boto3']}, |
|||
'images': ['static/description/banner.jpg'], |
|||
'license': 'AGPL-3', |
|||
'installable': True, |
|||
'auto_install': False, |
|||
'application': False, |
|||
} |
@ -0,0 +1,7 @@ |
|||
## Module <amazon_forecast_integration> |
|||
|
|||
#### 20.04.2024 |
|||
#### Version 16.0.1.0.0 |
|||
#### ADD |
|||
|
|||
- Initial Commit for Amazon Forecast Integration |
@ -0,0 +1,25 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Shafna K(odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from . import amazon_bucket |
|||
from . import amazon_dataset |
|||
from . import amazon_fetch_data |
|||
from . import res_config_settings |
@ -0,0 +1,136 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Shafna K(odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
import boto3 |
|||
import re |
|||
from odoo import fields, models |
|||
from odoo.exceptions import UserError |
|||
|
|||
|
|||
class AmazonBucket(models.Model): |
|||
"""Class to create an Amazon S3 bucket""" |
|||
_name = "amazon.bucket" |
|||
_description = "Amazon Bucket" |
|||
_rec_name = "bucket_name" |
|||
|
|||
bucket_name = fields.Char(string="Bucket Name", required=True, |
|||
help="""Provide the bucket name. |
|||
Eg: |
|||
- docexamplebucket1 |
|||
- log-delivery-march-2020 |
|||
- my-hosted-content""") |
|||
state = fields.Selection([ |
|||
('create_bucket', 'Create Bucket'), |
|||
('push_to_bucket', 'Push To bucket'), |
|||
('pushed', 'Pushed') |
|||
], help="States of bucket creation.", string="State", |
|||
default='create_bucket') |
|||
file_path = fields.Char(string="File Path", |
|||
help="Provide the file path of your data.") |
|||
s3_uri = fields.Char(string="S3 URI", help="After pushing the data to s3 " |
|||
"Bucket, URI will be computed.") |
|||
|
|||
def _validate_bucket_name(self, bucket_name): |
|||
if len(bucket_name) < 3 or len(bucket_name) > 63: |
|||
raise ValueError("Bucket name must be between 3 and 63 characters" |
|||
" long") |
|||
if not re.match("^[a-z0-9.-]+$", bucket_name): |
|||
raise ValueError("Bucket name can consist only of lowercase " |
|||
"letters, numbers, dots, and hyphens") |
|||
if not bucket_name[0].isalnum() or not bucket_name[-1].isalnum(): |
|||
raise ValueError("Bucket name must begin and end with a letter or" |
|||
" number") |
|||
if ".." in bucket_name: |
|||
raise ValueError("Bucket name must not contain two adjacent " |
|||
"periods") |
|||
if re.match(r"^\d+\.\d+\.\d+\.\d+$", bucket_name): |
|||
raise ValueError("Bucket name must not be formatted as an " |
|||
"IP address") |
|||
reserved_prefixes = ['xn--', 'sthree-', 'sthree-configurator-'] |
|||
reserved_suffixes = ['-s3alias', '--ol-s3'] |
|||
for prefix in reserved_prefixes: |
|||
if bucket_name.startswith(prefix): |
|||
raise ValueError("Bucket name must not start with the " |
|||
"prefix '{prefix}'") |
|||
for suffix in reserved_suffixes: |
|||
if bucket_name.endswith(suffix): |
|||
raise ValueError("Bucket name must not end with the" |
|||
" suffix '{suffix}'") |
|||
if '.' in bucket_name: |
|||
raise ValueError("Buckets used with Transfer Acceleration can't " |
|||
"have dots (.) in their names") |
|||
|
|||
def action_s3bucket(self): |
|||
"""Function to create an S3 bucket in Amazon""" |
|||
file = self.env['amazon.fetch.data'].get_file_path() |
|||
values = self.env['amazon.dataset'].forecast_values() |
|||
amazon_forecast = values['amazon_forecast'] |
|||
if amazon_forecast: |
|||
amazon_access_key = values['amazon_access_key'] |
|||
amazon_secret_access_key = values['amazon_secret_access_key'] |
|||
amazon_region = values['amazon_region'] |
|||
session = boto3.Session( |
|||
aws_access_key_id=amazon_access_key, |
|||
aws_secret_access_key=amazon_secret_access_key, |
|||
region_name=amazon_region |
|||
) |
|||
s3_client = session.client('s3') |
|||
bucket_name = self.bucket_name |
|||
try: |
|||
self._validate_bucket_name(bucket_name) |
|||
except ValueError as e: |
|||
raise UserError(e) |
|||
self.write({ |
|||
'file_path': file |
|||
}) |
|||
s3_client.create_bucket( |
|||
Bucket=bucket_name, |
|||
CreateBucketConfiguration={'LocationConstraint': 'ap-south-1'} |
|||
) |
|||
self.write({'state': "push_to_bucket"}) |
|||
|
|||
def action_s3bucket_push(self): |
|||
"""To push the data to Amazon S3 bucket""" |
|||
values = self.env['amazon.dataset'].forecast_values() |
|||
amazon_forecast = values['amazon_forecast'] |
|||
if amazon_forecast: |
|||
amazon_access_key = values['amazon_access_key'] |
|||
amazon_secret_access_key = values['amazon_secret_access_key'] |
|||
amazon_region = values['amazon_region'] |
|||
session = boto3.Session( |
|||
aws_access_key_id=amazon_access_key, |
|||
aws_secret_access_key=amazon_secret_access_key, |
|||
region_name=amazon_region |
|||
) |
|||
s3_client = session.client('s3') |
|||
s3_resource = session.resource('s3') |
|||
bucket = s3_resource.Bucket(self.bucket_name) |
|||
bucket_name = self.bucket_name |
|||
file_path = self.file_path |
|||
with open(file_path, 'rb') as file: |
|||
s3_client.put_object(Body=file, Bucket=bucket_name, |
|||
Key=file_path) |
|||
for object_summary in bucket.objects.all(): |
|||
object_key = object_summary.key |
|||
self.write({ |
|||
's3_uri': f"s3://{self.bucket_name}/{object_key}", |
|||
}) |
|||
self.write({'state': "pushed"}) |
@ -0,0 +1,602 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Shafna K(odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
import boto3 |
|||
import json |
|||
import time |
|||
from odoo import api, fields, models, _ |
|||
from odoo.exceptions import UserError |
|||
|
|||
|
|||
class AmazonDataset(models.Model): |
|||
"""Class to create a forecast of stock""" |
|||
_name = "amazon.dataset" |
|||
_description = "Amazon Dataset" |
|||
_rec_name = "table_name" |
|||
|
|||
table_name = fields.Char(string="Table Name", required=True, |
|||
help="Provide the table name.") |
|||
role_name = fields.Char(string="Role Name", |
|||
help="Provide the Role name.") |
|||
policy_name = fields.Char(string="Policy Name", |
|||
help="Provide the Policy name.") |
|||
dataset_group = fields.Char(string="Dataset Group", |
|||
help="Provide the Dataset Group name.") |
|||
dataset = fields.Char(string="Dataset", |
|||
help="Provide the Dataset name.") |
|||
state = fields.Selection([ |
|||
('table', "Table"), |
|||
('role', "Role"), |
|||
('kms', "KMS"), |
|||
('policy', "Policy"), |
|||
('dataset', "Dataset"), |
|||
('import_dataset', "Import Dataset"), |
|||
('predictor', "Predictor"), |
|||
('forecast', "Forecast"), |
|||
('query_forecast', "Query Forecast"), |
|||
], default="table", string="State", |
|||
help="States of dataset creation.") |
|||
table_arn = fields.Char(string="Table ARN", |
|||
help="Table arn will be computed based on table" |
|||
" name provided after creating the table.") |
|||
role_arn = fields.Char(string="Role Arn", help="Role Arn will be computed " |
|||
"after Role is created.") |
|||
policy_arn = fields.Char(string="Policy Arn", |
|||
help="Policy Arn will be created after the " |
|||
"policy is created.") |
|||
kms_alias = fields.Char(string="KMS Alias Name", |
|||
help="Provide an Alias name for KMS.") |
|||
kms_arn = fields.Char(string="KMS Arn", help="KMS Arn will be created " |
|||
"after KMS key is created.") |
|||
dataset_group_arn = fields.Char(string="Dataset Group Arn", |
|||
help="Dataset Group Arn will be created " |
|||
"after Dataset Group is created.") |
|||
dataset_arn = fields.Char(string="Dataset Arn", |
|||
help="Dataset Arn will be craeted after" |
|||
" Dataset is created.") |
|||
forecast_frequency = fields.Selection([ |
|||
('D', 'Days'), |
|||
('W', 'Weeks'), |
|||
('M', 'Months'), |
|||
('Y', 'Years'), |
|||
('T', 'Minutes'), |
|||
('H', 'Hours'), |
|||
], default='D', string="Forecast Frequency", help="Choose the frequency" |
|||
" for forecasting.") |
|||
import_job_name = fields.Char(string="Import Job Name", |
|||
help="Provide the import job name.") |
|||
import_job_arn = fields.Char(string="Import Job Arn", |
|||
help="Import job Arn will be computed after" |
|||
" import job is done.") |
|||
predictor_name = fields.Char(string="Predictor Name", |
|||
help="Provide a name for Predictor function.") |
|||
predictor_algorithm = fields.Selection([ |
|||
('arn:aws:forecast:::algorithm/ARIMA', 'ARIMA'), |
|||
('arn:aws:forecast:::algorithm/CNN-QR', 'CNN-QR'), |
|||
('arn:aws:forecast:::algorithm/NPTS', 'NPTS'), |
|||
('arn:aws:forecast:::algorithm/MQRNN', 'MQRNN'), |
|||
], string="Algorithm", default='arn:aws:forecast:::algorithm/ARIMA', |
|||
help="Choose desired Predictor Algorithm.") |
|||
predictor_arn = fields.Char(string="Predictor Arn", |
|||
help="Predictor Arn will be computed after " |
|||
"predictor function is created.") |
|||
forecast_name = fields.Char(string="Forecast Name", |
|||
help="Provide the name for forecast function.") |
|||
forecast_arn = fields.Char(string="Forecast Arn", |
|||
help="Forecast Arn will be computed after " |
|||
"forecasting is completed.") |
|||
item_id = fields.Char(string="Item id", |
|||
help="Provide the name of product you want to know " |
|||
"the forecasting.") |
|||
bucket_id = fields.Many2one('amazon.bucket', string="Bucket", |
|||
help="Choose the bucket name " |
|||
"from which the data must" |
|||
"be taken.") |
|||
|
|||
def forecast_values(self): |
|||
"""To connect with the Amazon Forecast services using credentials""" |
|||
amazon_forecast = self.env['ir.config_parameter'].sudo().get_param( |
|||
'amazon_forecast_integration.amazon_forecast') |
|||
amazon_access_key = self.env['ir.config_parameter'].sudo().get_param( |
|||
'amazon_forecast_integration.amazon_access_key') |
|||
amazon_secret_access_key = self.env[ |
|||
'ir.config_parameter'].sudo().get_param( |
|||
'amazon_forecast_integration.amazon_secret_access_key') |
|||
amazon_region = self.env['ir.config_parameter'].sudo().get_param( |
|||
'amazon_forecast_integration.amazon_region') |
|||
return { |
|||
'amazon_forecast': amazon_forecast, |
|||
'amazon_access_key': amazon_access_key, |
|||
'amazon_secret_access_key': amazon_secret_access_key, |
|||
'amazon_region': amazon_region, |
|||
} |
|||
|
|||
def action_create_table(self): |
|||
"""To create a dynamodb in Amazon Forecast""" |
|||
values = self.forecast_values() |
|||
amazon_forecast = values['amazon_forecast'] |
|||
if amazon_forecast: |
|||
amazon_access_key = values['amazon_access_key'] |
|||
amazon_secret_access_key = values['amazon_secret_access_key'] |
|||
amazon_region = values['amazon_region'] |
|||
session = boto3.Session( |
|||
aws_access_key_id=amazon_access_key, |
|||
aws_secret_access_key=amazon_secret_access_key, |
|||
region_name=amazon_region |
|||
) |
|||
dynamodb_client = session.client('dynamodb') |
|||
try: |
|||
response = dynamodb_client.create_table( |
|||
TableName=self.table_name, |
|||
AttributeDefinitions=[ |
|||
{ |
|||
'AttributeName': 'id', |
|||
'AttributeType': 'N' |
|||
} |
|||
], |
|||
KeySchema=[ |
|||
{ |
|||
'AttributeName': 'id', |
|||
'KeyType': 'HASH' |
|||
} |
|||
], |
|||
ProvisionedThroughput={ |
|||
'ReadCapacityUnits': 5, |
|||
'WriteCapacityUnits': 5 |
|||
} |
|||
) |
|||
self.write({ |
|||
'state': 'role', |
|||
'table_arn': response['TableDescription']['TableArn'] |
|||
}) |
|||
except dynamodb_client.exceptions.ClientError as e: |
|||
raise UserError(e) |
|||
|
|||
def action_create_role(self): |
|||
"""To create a Role for Forecasting""" |
|||
values = self.forecast_values() |
|||
amazon_forecast = values['amazon_forecast'] |
|||
if amazon_forecast: |
|||
amazon_access_key = values['amazon_access_key'] |
|||
amazon_secret_access_key = values['amazon_secret_access_key'] |
|||
amazon_region = values['amazon_region'] |
|||
session = boto3.Session( |
|||
aws_access_key_id=amazon_access_key, |
|||
aws_secret_access_key=amazon_secret_access_key, |
|||
region_name=amazon_region |
|||
) |
|||
assume_role_policy_document = { |
|||
"Version": "2012-10-17", |
|||
"Statement": [ |
|||
{ |
|||
"Effect": "Allow", |
|||
"Principal": { |
|||
"Service": "forecast.amazonaws.com" |
|||
}, |
|||
"Action": "sts:AssumeRole" |
|||
} |
|||
] |
|||
} |
|||
iam_client = session.client('iam') |
|||
try: |
|||
response = iam_client.create_role( |
|||
RoleName=self.role_name, |
|||
AssumeRolePolicyDocument=json.dumps( |
|||
assume_role_policy_document) |
|||
) |
|||
self.write({ |
|||
'state': 'kms', |
|||
'role_arn': response['Role']['Arn'] |
|||
}) |
|||
except iam_client.exceptions.ClientError as e: |
|||
raise UserError(e) |
|||
|
|||
def action_create_kms(self): |
|||
"""To create a Key Management Service in AWS""" |
|||
values = self.forecast_values() |
|||
amazon_forecast = values['amazon_forecast'] |
|||
if amazon_forecast: |
|||
amazon_access_key = values['amazon_access_key'] |
|||
amazon_secret_access_key = values['amazon_secret_access_key'] |
|||
amazon_region = values['amazon_region'] |
|||
session = boto3.Session( |
|||
aws_access_key_id=amazon_access_key, |
|||
aws_secret_access_key=amazon_secret_access_key, |
|||
region_name=amazon_region |
|||
) |
|||
kms_client = session.client('kms') |
|||
response = kms_client.create_key( |
|||
Description='KMS Key' |
|||
) |
|||
key_id = response['KeyMetadata']['KeyId'] |
|||
key_response = kms_client.describe_key(KeyId=key_id) |
|||
key_arn = key_response['KeyMetadata']['Arn'] |
|||
self.write({ |
|||
'kms_arn': key_arn, |
|||
}) |
|||
kms_client.create_alias( |
|||
AliasName='alias/'+self.kms_alias, |
|||
TargetKeyId=key_id |
|||
) |
|||
kms_client.create_grant( |
|||
KeyId=key_id, |
|||
GranteePrincipal=self.role_arn, |
|||
Operations=['Encrypt', 'Decrypt'] |
|||
) |
|||
self.write({ |
|||
'state': 'policy' |
|||
}) |
|||
return key_id |
|||
|
|||
def action_create_policy(self): |
|||
"""To create a policies for the role and attach it with the role""" |
|||
values = self.forecast_values() |
|||
amazon_forecast = values['amazon_forecast'] |
|||
if amazon_forecast: |
|||
amazon_access_key = values['amazon_access_key'] |
|||
amazon_secret_access_key = values['amazon_secret_access_key'] |
|||
amazon_region = values['amazon_region'] |
|||
session = boto3.Session( |
|||
aws_access_key_id=amazon_access_key, |
|||
aws_secret_access_key=amazon_secret_access_key, |
|||
region_name=amazon_region |
|||
) |
|||
iam_client = session.client('iam') |
|||
sts_client = session.client('sts') |
|||
response = sts_client.get_caller_identity() |
|||
account_id = response['Account'] |
|||
policy_name = self.policy_name |
|||
policy_document = { |
|||
"Version": "2012-10-17", |
|||
"Statement": [ |
|||
{ |
|||
"Effect": "Allow", |
|||
"Action": [ |
|||
"s3:ListBucket" |
|||
], |
|||
"Resource": "arn:aws:s3:::"+self.bucket_id.bucket_name |
|||
}, |
|||
{ |
|||
"Effect": "Allow", |
|||
"Action": [ |
|||
"s3:GetObject", |
|||
"s3:PutObject" |
|||
], |
|||
"Resource": |
|||
"arn:aws:s3:::"+self.bucket_id.bucket_name+"/*" |
|||
}, |
|||
{ |
|||
"Effect": "Allow", |
|||
"Action": [ |
|||
"dynamodb:PutItem", |
|||
"dynamodb:GetItem" |
|||
], |
|||
"Resource": self.table_arn |
|||
}, |
|||
{ |
|||
"Effect": "Allow", |
|||
"Action": [ |
|||
"kms:Encrypt", |
|||
"kms:Decrypt", |
|||
"kms:ReEncrypt*", |
|||
"kms:GenerateDataKey*", |
|||
"kms:DescribeKey", |
|||
"kms:CreateGrant" |
|||
], |
|||
"Resource": self.kms_arn |
|||
} |
|||
] |
|||
} |
|||
response = iam_client.create_policy( |
|||
PolicyName=policy_name, |
|||
PolicyDocument=json.dumps(policy_document), |
|||
) |
|||
self.write({ |
|||
'policy_arn': response['Policy']['Arn'] |
|||
}) |
|||
try: |
|||
iam_client.put_role_policy( |
|||
RoleName=self.role_name, |
|||
PolicyName=policy_name, |
|||
PolicyDocument=json.dumps(policy_document) |
|||
) |
|||
except Exception as e: |
|||
raise UserError(e) |
|||
try: |
|||
policy_arn1 = 'arn:aws:iam::aws:policy/AmazonS3FullAccess' |
|||
policy_arn2 = ( |
|||
'arn:aws:iam::'+account_id+':policy/'+self.policy_name) |
|||
iam_client.attach_role_policy( |
|||
RoleName=self.role_name, |
|||
PolicyArn=policy_arn1 |
|||
) |
|||
iam_client.attach_role_policy( |
|||
RoleName=self.role_name, |
|||
PolicyArn=policy_arn2 |
|||
) |
|||
self.write({ |
|||
'state': 'dataset' |
|||
}) |
|||
except iam_client.exceptions.ClientError as e: |
|||
raise UserError(e) |
|||
except iam_client.exceptions.ClientError as e: |
|||
raise UserError(e) |
|||
|
|||
def action_create_dataset(self): |
|||
"""To create required Dataset for forecasting""" |
|||
values = self.forecast_values() |
|||
amazon_forecast = values['amazon_forecast'] |
|||
if amazon_forecast: |
|||
amazon_access_key = values['amazon_access_key'] |
|||
amazon_secret_access_key = values['amazon_secret_access_key'] |
|||
amazon_region = values['amazon_region'] |
|||
session = boto3.Session( |
|||
aws_access_key_id=amazon_access_key, |
|||
aws_secret_access_key=amazon_secret_access_key, |
|||
region_name=amazon_region |
|||
) |
|||
dataset_group_name = self.dataset_group |
|||
forecast_client = session.client('forecast') |
|||
try: |
|||
dataset_group_response = forecast_client.create_dataset_group( |
|||
DatasetGroupName=dataset_group_name, |
|||
Domain='RETAIL', |
|||
Tags=[ |
|||
{'Key': 'Name', 'Value': dataset_group_name} |
|||
] |
|||
) |
|||
self.write({'dataset_group_arn': dataset_group_response[ |
|||
'DatasetGroupArn']}) |
|||
dataset_name = self.dataset |
|||
except forecast_client.exceptions.ClientError as e: |
|||
raise UserError(e) |
|||
try: |
|||
schema = { |
|||
"Attributes": [ |
|||
{"AttributeName": "item_id", |
|||
"AttributeType": "string"}, |
|||
{"AttributeName": "timestamp", |
|||
"AttributeType": "timestamp"}, |
|||
{"AttributeName": "demand", |
|||
"AttributeType": "float"}, |
|||
{"AttributeName": "id", "AttributeType": "string"}, |
|||
{"AttributeName": "reference", |
|||
"AttributeType": "string"}, |
|||
{"AttributeName": "location_id", |
|||
"AttributeType": "string"}, |
|||
{"AttributeName": "location_dest_id", |
|||
"AttributeType": "string"}, |
|||
{"AttributeName": "origin", |
|||
"AttributeType": "string"}, |
|||
] |
|||
} |
|||
dataset_response = forecast_client.create_dataset( |
|||
DatasetName=dataset_name, |
|||
DatasetType='TARGET_TIME_SERIES', |
|||
Domain='RETAIL', |
|||
DataFrequency=self.forecast_frequency, |
|||
Schema=schema, |
|||
EncryptionConfig={ |
|||
'RoleArn': self.role_arn, |
|||
'KMSKeyArn': self.kms_arn, |
|||
} |
|||
) |
|||
self.write({ |
|||
'dataset_arn': dataset_response['DatasetArn'] |
|||
}) |
|||
forecast_client.update_dataset_group( |
|||
DatasetGroupArn=self.dataset_group_arn, |
|||
DatasetArns=[self.dataset_arn]) |
|||
self.write({ |
|||
'state': 'import_dataset' |
|||
}) |
|||
except forecast_client.exceptions.ClientError as e: |
|||
raise UserError(e) |
|||
|
|||
def action_import_dataset(self): |
|||
"""To import dataset from Amazon S3 bucket""" |
|||
values = self.forecast_values() |
|||
amazon_forecast = values['amazon_forecast'] |
|||
if amazon_forecast: |
|||
amazon_access_key = values['amazon_access_key'] |
|||
amazon_secret_access_key = values['amazon_secret_access_key'] |
|||
amazon_region = values['amazon_region'] |
|||
session = boto3.Session( |
|||
aws_access_key_id=amazon_access_key, |
|||
aws_secret_access_key=amazon_secret_access_key, |
|||
region_name=amazon_region |
|||
) |
|||
forecast_client = session.client('forecast') |
|||
try: |
|||
response = forecast_client.create_dataset_import_job( |
|||
DatasetImportJobName=self.import_job_name, |
|||
DatasetArn=self.dataset_arn, |
|||
DataSource={ |
|||
'S3Config': { |
|||
'Path': self.bucket_id.s3_uri, |
|||
'RoleArn': self.role_arn |
|||
} |
|||
} |
|||
) |
|||
self.write({ |
|||
'import_job_arn': response['DatasetImportJobArn'], |
|||
'state': 'predictor' |
|||
}) |
|||
while True: |
|||
response = forecast_client.describe_dataset_import_job( |
|||
DatasetImportJobArn=self.import_job_arn) |
|||
status = response['Status'] |
|||
if status == 'ACTIVE': |
|||
break |
|||
elif status == 'FAILED' or status == 'CREATE_FAILED': |
|||
raise UserError(_('Error: Dataset Import Job failed.')) |
|||
break |
|||
else: |
|||
time.sleep(10) |
|||
except forecast_client.exceptions.ClientError as e: |
|||
raise UserError(e) |
|||
|
|||
def action_create_predictor(self): |
|||
"""To create the predictor function for forecasting""" |
|||
values = self.forecast_values() |
|||
amazon_forecast = values['amazon_forecast'] |
|||
if amazon_forecast: |
|||
amazon_access_key = values['amazon_access_key'] |
|||
amazon_secret_access_key = values['amazon_secret_access_key'] |
|||
amazon_region = values['amazon_region'] |
|||
session = boto3.Session( |
|||
aws_access_key_id=amazon_access_key, |
|||
aws_secret_access_key=amazon_secret_access_key, |
|||
region_name=amazon_region |
|||
) |
|||
forecast_client = session.client('forecast') |
|||
try: |
|||
response_group = forecast_client.describe_dataset_group( |
|||
DatasetGroupArn=self.dataset_group_arn) |
|||
dataset_arns = response_group['DatasetArns'] |
|||
while True: |
|||
all_datasets_imported = True |
|||
for dataset_arn in dataset_arns: |
|||
response = forecast_client.list_dataset_import_jobs( |
|||
Filters=[{'Key': 'DatasetArn', |
|||
'Value': dataset_arn, |
|||
'Condition': 'IS'}]) |
|||
import_jobs = response["DatasetImportJobs"] |
|||
if (len(import_jobs) == 0 or |
|||
import_jobs[0]["Status"] != "ACTIVE"): |
|||
all_datasets_imported = False |
|||
break |
|||
if all_datasets_imported: |
|||
break |
|||
time.sleep(10) |
|||
response = forecast_client.describe_dataset( |
|||
DatasetArn=self.dataset_arn) |
|||
featurization_config = response['DataFrequency'] |
|||
response = forecast_client.create_predictor( |
|||
PredictorName=self.predictor_name, |
|||
AlgorithmArn=self.predictor_algorithm, |
|||
ForecastHorizon=1, |
|||
PerformAutoML=False, |
|||
PerformHPO=False, |
|||
InputDataConfig={ |
|||
'DatasetGroupArn': self.dataset_group_arn, |
|||
}, |
|||
FeaturizationConfig={ |
|||
'ForecastFrequency': featurization_config, |
|||
} |
|||
) |
|||
self.write({ |
|||
'predictor_arn': response['PredictorArn'], |
|||
'state': 'forecast' |
|||
}) |
|||
except forecast_client.exceptions.ClientError as e: |
|||
raise UserError(e) |
|||
|
|||
def action_create_forecast(self): |
|||
"""To create the forecast based on our data""" |
|||
values = self.forecast_values() |
|||
amazon_forecast = values['amazon_forecast'] |
|||
if amazon_forecast: |
|||
amazon_access_key = values['amazon_access_key'] |
|||
amazon_secret_access_key = values['amazon_secret_access_key'] |
|||
amazon_region = values['amazon_region'] |
|||
session = boto3.Session( |
|||
aws_access_key_id=amazon_access_key, |
|||
aws_secret_access_key=amazon_secret_access_key, |
|||
region_name=amazon_region |
|||
) |
|||
forecast_client = session.client('forecast') |
|||
try: |
|||
response = forecast_client.create_forecast( |
|||
ForecastName=self.forecast_name, |
|||
PredictorArn=self.predictor_arn |
|||
) |
|||
self.write({ |
|||
'forecast_arn': response['ForecastArn'], |
|||
'state': 'query_forecast' |
|||
}) |
|||
while True: |
|||
response = forecast_client.describe_forecast( |
|||
ForecastArn=response['ForecastArn']) |
|||
status = response['Status'] |
|||
if status == 'ACTIVE': |
|||
break |
|||
elif status == 'FAILED': |
|||
raise UserError(_('Error: Forecast creation failed.')) |
|||
break |
|||
else: |
|||
time.sleep(10) |
|||
except forecast_client.exceptions.ClientError as e: |
|||
raise UserError(e) |
|||
time.sleep(60) |
|||
|
|||
def query_forecast(self): |
|||
"""To get the forecast result""" |
|||
values = self.forecast_values() |
|||
amazon_forecast = values['amazon_forecast'] |
|||
if amazon_forecast: |
|||
amazon_access_key = values['amazon_access_key'] |
|||
amazon_secret_access_key = values['amazon_secret_access_key'] |
|||
amazon_region = values['amazon_region'] |
|||
session = boto3.Session( |
|||
aws_access_key_id=amazon_access_key, |
|||
aws_secret_access_key=amazon_secret_access_key, |
|||
region_name=amazon_region |
|||
) |
|||
forecast_client = session.client('forecastquery') |
|||
try: |
|||
forecast_client.query_forecast( |
|||
ForecastArn=self.forecast_arn, |
|||
Filters={ |
|||
'item_id': self.item_id |
|||
} |
|||
) |
|||
return { |
|||
'type': 'ir.actions.client', |
|||
'tag': 'forecast', |
|||
} |
|||
except forecast_client.exceptions.ClientError as e: |
|||
raise UserError(e) |
|||
|
|||
@api.model |
|||
def get_query_result(self): |
|||
"""To get the response from the query forecast""" |
|||
values = self.forecast_values() |
|||
amazon_forecast = values['amazon_forecast'] |
|||
if amazon_forecast: |
|||
amazon_access_key = values['amazon_access_key'] |
|||
amazon_secret_access_key = values['amazon_secret_access_key'] |
|||
amazon_region = values['amazon_region'] |
|||
session = boto3.Session( |
|||
aws_access_key_id=amazon_access_key, |
|||
aws_secret_access_key=amazon_secret_access_key, |
|||
region_name=amazon_region |
|||
) |
|||
forecast_client = session.client('forecastquery') |
|||
data = self.search([], limit=1) |
|||
response = forecast_client.query_forecast( |
|||
ForecastArn=data.forecast_arn, |
|||
Filters={ |
|||
'item_id': data.item_id |
|||
} |
|||
) |
|||
forecast_result = response['Forecast']['Predictions'] |
|||
return forecast_result |
@ -0,0 +1,86 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Shafna K(odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
import csv |
|||
import xmlrpc.client |
|||
from odoo import fields, models, _ |
|||
|
|||
|
|||
class AmazonFetchData(models.Model): |
|||
"""Class for fetching the data from our database""" |
|||
_name = "amazon.fetch.data" |
|||
_description = "To Fetch Data" |
|||
_rec_name = "db_name" |
|||
|
|||
url = fields.Char(string="URL", required=True, |
|||
help="Provide the URL in correct format.") |
|||
db_name = fields.Char(string="Database Name", required=True, |
|||
help="Provide the database name.") |
|||
db_username = fields.Char(string="Database Username", required=True, |
|||
help="Provide the Username.") |
|||
db_password = fields.Char(string="Database Password", required=True, |
|||
help="Provide the db password.") |
|||
csv_file_path = fields.Char(string="File Path", required=True, |
|||
help="Provide the file location path.") |
|||
|
|||
def action_fetch_data(self): |
|||
"""To fetch the data from the database""" |
|||
common = xmlrpc.client.ServerProxy(f'{self.url}/xmlrpc/2/common') |
|||
uid = common.authenticate(self.db_name, self.db_username, |
|||
self.db_password, {}) |
|||
model = xmlrpc.client.ServerProxy(f'{self.url}/xmlrpc/2/object') |
|||
model_name = 'stock.move' |
|||
field = ['product_id', 'date', 'product_uom_qty', 'id', 'reference', |
|||
'location_id', 'location_dest_id', 'origin'] |
|||
data = model.execute_kw(self.db_name, uid, self.db_password, |
|||
model_name, 'search_read', |
|||
[[]], {'fields': field}) |
|||
for item in data: |
|||
item['product_id'] = item['product_id'][1] if item[ |
|||
'product_id'] else '' |
|||
item['location_id'] = item['location_id'][1] if item[ |
|||
'location_id'] else '' |
|||
item['location_dest_id'] = item['location_dest_id'][1] if item[ |
|||
'location_dest_id'] else '' |
|||
for items in data: |
|||
items['item_id'] = items.pop('product_id', '') |
|||
items['timestamp'] = items.pop('date', '') |
|||
items['demand'] = items.pop('product_uom_qty', '') |
|||
|
|||
new_headers = ['item_id', 'timestamp', 'demand', 'id', 'reference', |
|||
'location_id', 'location_dest_id', 'origin'] |
|||
with open(self.csv_file_path, 'w', newline='') as csv_file: |
|||
writer = csv.DictWriter(csv_file, fieldnames=new_headers) |
|||
writer.writeheader() |
|||
writer.writerows(data) |
|||
return { |
|||
'name': _('Push to Bucket'), |
|||
'type': 'ir.actions.act_window', |
|||
'res_model': 'amazon.bucket', |
|||
'view_mode': 'form', |
|||
'target': 'current' |
|||
} |
|||
|
|||
def get_file_path(self): |
|||
"""To get the file path""" |
|||
data = self.search([], limit=1) |
|||
file_path = data.csv_file_path |
|||
return file_path |
@ -0,0 +1,77 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Shafna K(odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
import boto3 |
|||
from botocore.exceptions import ClientError |
|||
from odoo import fields, models, _ |
|||
from odoo.exceptions import UserError |
|||
|
|||
|
|||
class ResConfigSettings(models.TransientModel): |
|||
"""Class inheriting the res config settings for adding fields for the |
|||
authentication of AWS with Odoo""" |
|||
_inherit = 'res.config.settings' |
|||
|
|||
amazon_forecast = fields.Boolean( |
|||
string="Amazon Forecast", required=True, |
|||
config_parameter='amazon_forecast_integration.amazon_forecast', |
|||
help="Enable to use Amazon Forecast services.") |
|||
amazon_access_key = fields.Char( |
|||
string="Access Key", help="Provide the access key.", required=True, |
|||
config_parameter='amazon_forecast_integration.amazon_access_key') |
|||
amazon_secret_access_key = fields.Char( |
|||
string="Secret Access Key", required=True, |
|||
config_parameter='amazon_forecast_integration.amazon_secret_access_key', |
|||
help="Provide the secret access key.") |
|||
amazon_region = fields.Char( |
|||
string="Access Key", help="Provide the region.", required=True, |
|||
config_parameter='amazon_forecast_integration.amazon_amazon_region') |
|||
|
|||
def authenticate_amazon_forecast(self): |
|||
"""Function to authenticate the AWS connection with Odoo""" |
|||
try: |
|||
session = boto3.Session( |
|||
aws_access_key_id=self.amazon_access_key, |
|||
aws_secret_access_key=self.amazon_secret_access_key, |
|||
region_name=self.amazon_region |
|||
) |
|||
iam_client = session.client('iam') |
|||
response = iam_client.list_users() |
|||
return response |
|||
except ClientError: |
|||
error_message = _('Invalid Amazon Forecast credentials. Please' |
|||
' verify your access key and secret key.') |
|||
raise UserError(error_message) |
|||
|
|||
def set_values(self): |
|||
"""To set the values in the corresponding fields""" |
|||
super().set_values() |
|||
if self.amazon_forecast: |
|||
self.authenticate_amazon_forecast() |
|||
self.env['ir.config_parameter'].set_param( |
|||
'amazon_forecast_integration.amazon_forecast_access_key', |
|||
self.amazon_access_key or '') |
|||
self.env['ir.config_parameter'].set_param( |
|||
'amazon_forecast_integration.amazon_forecast_secret_key', |
|||
self.amazon_secret_access_key or '') |
|||
self.env['ir.config_parameter'].set_param( |
|||
'amazon_forecast_integration.amazon_region', |
|||
self.amazon_region or '') |
|
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 589 B |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 967 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 105 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 96 KiB |
After Width: | Height: | Size: 86 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 77 KiB |
After Width: | Height: | Size: 193 KiB |
After Width: | Height: | Size: 148 KiB |
After Width: | Height: | Size: 133 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 71 KiB |
After Width: | Height: | Size: 75 KiB |
After Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 87 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 117 KiB |
After Width: | Height: | Size: 138 KiB |
After Width: | Height: | Size: 158 KiB |
After Width: | Height: | Size: 172 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 373 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 9.0 KiB |
@ -0,0 +1,657 @@ |
|||
<div style="background-color: #714B67; height: 810px; width: 100%; padding: 15px; position: relative;"> |
|||
<!-- TITLE BAR --> |
|||
<div class="d-flex align-items-center justify-content-between" |
|||
style="border-bottom: 1px solid #875A7B; padding: 15px; display: flex; justify-content: space-between; align-items: center;"> |
|||
<img src="assets/misc/cybrosys-logo.png" width="42" height="42" |
|||
style="width: 42px; height: 42px;"/> |
|||
<div> |
|||
<div style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;" |
|||
class="mr-2"> |
|||
<i class="fa fa-check mr-1"></i>Enterprise |
|||
</div> |
|||
<div style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;" |
|||
class="mr-2"> |
|||
<i class="fa fa-check mr-1"></i>Odoo.sh |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END OF TITLE BAR --> |
|||
<div class="container"> |
|||
<div class="row"> |
|||
<div class="col-sm-12 col-md-12 col-lg-12"> |
|||
<!-- APP HERO --> |
|||
<h1 style="color: #FFFFFF; font-weight: bolder; font-size: 50px; text-align: center; margin-top: 50px;"> |
|||
Amazon Forecast Integration |
|||
</h1> |
|||
<p style="color:#FFFFFF; padding: 8px 15px; text-align: center; font-size: 24px;"> |
|||
This module helps to create Forecast of our Stock based on Demand. |
|||
</p> |
|||
<!-- END OF APP HERO --> |
|||
<img src="assets/screenshots/forecast.gif" class="img-responsive" |
|||
style="width: 100%; margin-left: auto; margin-right: auto;"/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- NAVIGATION SECTION --> |
|||
<div class="d-flex align-items-center" |
|||
style="border-bottom: 2px solid #714B67; padding: 15px 0px; margin-top: 300px;"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" |
|||
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/compass.png"/> |
|||
</div> |
|||
<h2 class="mt-2" |
|||
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
|||
Explore This Module</h2> |
|||
</div> |
|||
<div class="row my-4" style="font-family: 'Montserrat', sans-serif;"> |
|||
<div class="col-sm-12 col-md-6 my-3"> |
|||
<a href="#overview"> |
|||
<div class="d-flex justify-content-between align-items-center" |
|||
style="background-color: #f5f5f5; padding: 30px; width: 100%;"> |
|||
<div> |
|||
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Overview</span> |
|||
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">Learn more about this module</span> |
|||
</div> |
|||
<img src="assets/misc/right-arrow.png" width="36" height="36"/> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div class="col-sm-12 col-md-6 my-3"> |
|||
<a href="#features"> |
|||
<div class="d-flex justify-content-between align-items-center" |
|||
style="background-color: #f5f5f5; padding: 30px; width: 100%;"> |
|||
<div> |
|||
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Features</span> |
|||
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View features of this module</span> |
|||
</div> |
|||
<img src="assets/misc/right-arrow.png" width="36" height="36"/> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div class="col-sm-12 col-md-6 my-3"> |
|||
<a href="#screenshots"> |
|||
<div class="d-flex justify-content-between align-items-center" |
|||
style="background-color: #f5f5f5; padding: 30px; width: 100%;"> |
|||
<div> |
|||
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Screenshots</span> |
|||
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View screenshots for this module</span> |
|||
</div> |
|||
<img src="assets/misc/right-arrow.png" width="36" height="36"/> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
<!-- END OF NAVIGATION SECTION --> |
|||
<!-- OVERVIEW SECTION --> |
|||
<div class="d-flex align-items-center" |
|||
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="overview"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" |
|||
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/pie-chart.png"/> |
|||
</div> |
|||
<h2 class="mt-2" |
|||
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
|||
Overview |
|||
</h2> |
|||
</div> |
|||
<div class="row" |
|||
style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;"> |
|||
<div class="col-sm-12 py-4"> |
|||
This module helps to get the Forecast Report of our Stock based on the |
|||
historical Time series Data we provide. |
|||
</div> |
|||
</div> |
|||
<!-- END OF OVERVIEW SECTION --> |
|||
<!-- FEATURES SECTION --> |
|||
<div class="d-flex align-items-center" |
|||
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="features"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" |
|||
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/features.png"/> |
|||
</div> |
|||
<h2 class="mt-2" |
|||
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
|||
Features |
|||
</h2> |
|||
</div> |
|||
<div class="row" |
|||
style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;"> |
|||
<div class="col-sm-12 col-md-6"> |
|||
<div class="d-flex align-items-center" |
|||
style="margin-top: 30px; margin-bottom: 30px"> |
|||
<img src="assets/misc/check-box.png" class="mr-2"/> |
|||
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> Utilize Amazon Forecast to generate Accurate |
|||
Demand Forecasts based on historical data from Odoo.</span> |
|||
</div> |
|||
<div class="d-flex align-items-center" |
|||
style="margin-top: 30px; margin-bottom: 30px"> |
|||
<img src="assets/misc/check-box.png" class="mr-2"/> |
|||
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">The Forecasts can be used to optimize Inventory |
|||
levels and plan Procurement.</span> |
|||
</div> |
|||
<div class="d-flex align-items-center" |
|||
style="margin-top: 30px; margin-bottom: 30px"> |
|||
<img src="assets/misc/check-box.png" class="mr-2"/> |
|||
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Forecasting helps to prevent Stock outs and |
|||
Overstock situations, reducing holding Costs and improving |
|||
Customer satisfaction.</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END OF FEATURES SECTION --> |
|||
<!-- SCREENSHOTS SECTION --> |
|||
<div class="d-flex align-items-center" |
|||
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" |
|||
id="screenshots"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" |
|||
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/pictures.png"/> |
|||
</div> |
|||
<h2 class="mt-2" |
|||
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
|||
Screenshots |
|||
</h2> |
|||
</div> |
|||
<div class="row"> |
|||
<div class="col-sm-12"> |
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
|||
Login to the Amazon Account and Click on Security |
|||
Credentials to Create Access key. |
|||
</h3> |
|||
<img src="assets/screenshots/forecast-01.png" class="img-thumbnail"> |
|||
</div> |
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
|||
Note down the Access Key and the Secret Access Key generated |
|||
when Creating the Access Key. |
|||
</h3> |
|||
<img src="assets/screenshots/forecast-02.png" class="img-thumbnail"> |
|||
</div> |
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
|||
Provide these Access Key, Secret Access Key and the AWS region |
|||
in Configuration Settings of Inventory. |
|||
</h3> |
|||
<img src="assets/screenshots/forecast-03.png" class="img-thumbnail"> |
|||
</div> |
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
|||
Click on the Menu Item Amazon Forecast and Click on Fetch Data |
|||
to Fetch the Data for Forecasting,Note that for Forecasting, a |
|||
Historical Data is needed to get the Result. |
|||
</h3> |
|||
<img src="assets/screenshots/forecast-04.png" class="img-thumbnail"> |
|||
</div> |
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
|||
Click on the Fetch Data button for Fetching Data. |
|||
</h3> |
|||
<img src="assets/screenshots/forecast-05.png" class="img-thumbnail"> |
|||
</div> |
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
|||
Now Click on Amazon Forecast and Click on Bucket to Create |
|||
Bucket in Amazon S3.Provide a name for the bucket meeting the |
|||
naming format allowed in S3. |
|||
</h3> |
|||
<img src="assets/screenshots/forecast-06.png" class="img-thumbnail"> |
|||
</div> |
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
|||
Click on Push to Bucket Button to push the Data to Amazon S3 |
|||
Bucket. |
|||
</h3> |
|||
<img src="assets/screenshots/forecast-07.png" class="img-thumbnail"> |
|||
</div> |
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
|||
S3 URI field will be Updated and state is changed to Pushed. |
|||
</h3> |
|||
<img src="assets/screenshots/forecast-08.png" class="img-thumbnail"> |
|||
</div> |
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
|||
Next, Click on Forecast Menu and Create a Table in Dynamodb |
|||
and then Table Arn wil be Updated. |
|||
</h3> |
|||
<img src="assets/screenshots/forecast-09.png" class="img-thumbnail"> |
|||
</div> |
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
|||
Create Role by clicking on Create Role Button after providing |
|||
the Role Name. |
|||
</h3> |
|||
<img src="assets/screenshots/forecast-10.png" class="img-thumbnail"> |
|||
</div> |
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
|||
Choose the Bucket Name from the Bucket List and Create a KMS |
|||
Key by giving KMS Alias Name.KMS Arn will be Updated. |
|||
</h3> |
|||
<img src="assets/screenshots/forecast-11.png" class="img-thumbnail"> |
|||
</div> |
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
|||
Create Policy by giving policy name and Policy Arn will be |
|||
Updated. |
|||
</h3> |
|||
<img src="assets/screenshots/forecast-12.png" class="img-thumbnail"> |
|||
</div> |
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
|||
Create Dataset Group and Dataset by Clicking on Create Dataset |
|||
after providing the Dataset Group Name and Dataset Name. |
|||
</h3> |
|||
<img src="assets/screenshots/forecast-13.png" class="img-thumbnail"> |
|||
</div> |
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
|||
Import the Dataset from the S3 Bucket by Clicking on Import |
|||
Dataset Job After giving the Import Job Name. This requires |
|||
some time and ensure that the Data we are using have enough |
|||
historical Data. |
|||
</h3> |
|||
<img src="assets/screenshots/forecast-14.png" class="img-thumbnail"> |
|||
</div> |
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
|||
After Importing, now you can Create Predictor function by |
|||
giving Predictor Name and then CLicking on Create Predictor |
|||
Button. |
|||
</h3> |
|||
<img src="assets/screenshots/forecast-15.png" class="img-thumbnail"> |
|||
</div> |
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
|||
After completing the Predictor function Creation, Create |
|||
Forecast by giving the Forecast Name and the Item Id and then |
|||
the Forecast Arn will be Updated. |
|||
</h3> |
|||
<img src="assets/screenshots/forecast-16.png" class="img-thumbnail"> |
|||
</div> |
|||
<div style="display: block; margin: 30px auto;"> |
|||
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
|||
Clicking on the Query Forecast Button, you can get the Forecast |
|||
Graph. |
|||
</h3> |
|||
<img src="assets/screenshots/forecast-17.png" class="img-thumbnail"> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END OF SCREENSHOTS SECTION --> |
|||
<!-- RELATED PRODUCTS --> |
|||
<div class="d-flex align-items-center" |
|||
style="border-bottom: 2px solid #714B67; padding: 15px 0px;"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" |
|||
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/categories.png"/> |
|||
</div> |
|||
<h2 class="mt-2" |
|||
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
|||
Related Products |
|||
</h2> |
|||
</div> |
|||
<div class="row"> |
|||
<div class="col-sm-12"> |
|||
<div id="demo1" class="row carousel slide" data-ride="carousel"> |
|||
<!-- The slideshow --> |
|||
<div class="carousel-inner" style="padding: 30px;"> |
|||
<div class="carousel-item" style="min-height: 198.656px;"> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
|||
style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/16.0/inventory_turnover_report_analysis/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-radius: 0px;" |
|||
src="assets/modules/1.jpg"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
|||
style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/16.0/product_brand_inventory/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-radius: 0px;" |
|||
src="assets/modules/2.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
|||
style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/16.0/low_stocks_product_alert/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-radius: 0px;" |
|||
src="assets/modules/3.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
<div class="carousel-item active" |
|||
style="min-height: 198.656px;"> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
|||
style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/16.0/stock_intercompany_transfer/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-radius: 0px;" |
|||
src="assets/modules/4.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
|||
style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/16.0/product_deletion/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-radius: 0px;" |
|||
src="assets/modules/5.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
|||
style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/16.0/quick_stock_movement/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-radius: 0px;" |
|||
src="assets/modules/6.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- Left and right controls --> |
|||
<a class="carousel-control-prev" href="#demo1" data-slide="prev" |
|||
style="width:35px; color:#000"> <span |
|||
class="carousel-control-prev-icon"><i |
|||
class="fa fa-chevron-left" |
|||
style="font-size:24px"></i></span> |
|||
</a> <a class="carousel-control-next" href="#demo1" |
|||
data-slide="next" style="width:35px; color:#000"> |
|||
<span class="carousel-control-next-icon"><i |
|||
class="fa fa-chevron-right" |
|||
style="font-size:24px"></i></span> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END OF RELATED PRODUCTS --> |
|||
<!-- OUR SERVICES --> |
|||
<div class="d-flex align-items-center" |
|||
style="border-bottom: 2px solid #714B67; padding: 15px 0px;"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" |
|||
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/star.png"/> |
|||
</div> |
|||
<h2 class="mt-2" |
|||
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
|||
Our Services</h2> |
|||
</div> |
|||
<div class="container my-5"> |
|||
<div class="row"> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/cogs.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo Customization</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/wrench.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo Implementation</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/lifebuoy.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo Support</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/user.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Hire Odoo Developer</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #54a0ff !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/puzzle.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo Integration</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/update.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo Migration</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/consultation.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo Consultancy</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/training.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo Implementation</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/license.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo Licensing Consultancy</h6> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END OF OUR SERVICES --> |
|||
<!-- OUR INDUSTRIES --> |
|||
<div class="d-flex align-items-center" |
|||
style="border-bottom: 2px solid #714B67; padding: 15px 0px;"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" |
|||
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/corporate.png"/> |
|||
</div> |
|||
<h2 class="mt-2" |
|||
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
|||
Our Industries |
|||
</h2> |
|||
</div> |
|||
<div class="container my-5"> |
|||
<div class="row"> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/trading-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Trading</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Easily procure and sell your products</p> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/pos-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
POS</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Easy configuration and convivial experience</p> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/education-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Education</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
A platform for educational management</p> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/manufacturing-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Manufacturing</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Plan, track and schedule your operations</p> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/ecom-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
E-commerce & Website</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Mobile friendly, awe-inspiring product pages</p> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/service-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Service Management</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Keep track of services and invoice</p> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/restaurant-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Restaurant</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Run your bar or restaurant methodically</p> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/hotel-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Hotel Management</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
An all-inclusive hotel management application</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END OF OUR INDUSTRIES --> |
|||
<!-- SUPPORT --> |
|||
<div class="d-flex align-items-center" |
|||
style="border-bottom: 2px solid #714B67; padding: 15px 0px;"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" |
|||
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/customer-support.png"/> |
|||
</div> |
|||
<h2 class="mt-2" |
|||
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
|||
Support |
|||
</h2> |
|||
</div> |
|||
<div class="container mt-5"> |
|||
<div class="row"> |
|||
<div class="col-sm-12 col-md-6"> |
|||
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;"> |
|||
<div class="mr-4 d-flex justify-content-center align-items-center" |
|||
style="background-color: #714B67; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;"> |
|||
<img src="assets/misc/support.png" height="48" width="48" |
|||
style="width: 42px; height: 42px;"/> |
|||
</div> |
|||
<div> |
|||
<h4>Need Help?</h4> |
|||
<p style="line-height: 100%;">Got questions or need help? |
|||
Get in touch.</p> |
|||
<a href="mailto:odoo@cybrosys.com"> |
|||
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;"> |
|||
odoo@cybrosys.com</p> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-sm-12 col-md-6"> |
|||
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;"> |
|||
<div class="mr-4 d-flex justify-content-center align-items-center" |
|||
style="background-color: #2AC44D; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;"> |
|||
<img src="assets/misc/whatsapp.png" height="52" width="52" |
|||
style="width: 52px; height: 52px;"/> |
|||
</div> |
|||
<div> |
|||
<h4>WhatsApp</h4> |
|||
<p style="line-height: 100%;">Say hi to us on WhatsApp!</p> |
|||
<a href="https://api.whatsapp.com/send?phone=918606827707"> |
|||
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;"> |
|||
+91 86068 27707</p> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="row"> |
|||
<div class="col-sm-12 my-5 d-flex justify-content-center align-items-center"> |
|||
<img src="assets/misc/logo.png" width="144" height="31" |
|||
style="width:144px; height: 31px; margin-top: 40px;"/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END OF SUPPORT --> |
@ -0,0 +1,97 @@ |
|||
/** @odoo-module **/ |
|||
|
|||
/** |
|||
* This module defines a custom Odoo web client action 'forecast'. |
|||
* The action generates a scatter chart to display forecast data from the |
|||
'amazon.dataset' model. |
|||
* The chart represents forecast data for three points: p10, p50, and p90. |
|||
*/ |
|||
import { registry } from '@web/core/registry'; |
|||
const actionRegistry = registry.category("actions"); |
|||
const { useRef, onMounted, useState } = owl; |
|||
import rpc from 'web.rpc'; |
|||
import { browser } from '@web/core/browser/browser'; |
|||
const { Component } = owl; |
|||
|
|||
class ForecastReport extends Component{ |
|||
/** |
|||
* It is responsible for initializing the component and its state. |
|||
*/ |
|||
setup(){ |
|||
super.setup(...arguments); |
|||
this.forecastBarGraph = useRef("bubble-chart"); |
|||
this.FinalData = useState({ |
|||
ForecastData:[], |
|||
}) |
|||
onMounted(async () =>{ |
|||
await this.forecastGraph(); |
|||
}); |
|||
} |
|||
/** |
|||
* The 'forecastGraph' function asynchronously retrieves forecast data from the 'amazon.dataset' model using RPC. |
|||
* It then generates a scatter chart using the Chart.js library to visualize the data. |
|||
*/ |
|||
async forecastGraph(){ |
|||
let abc = await rpc.query({ |
|||
model:'amazon.dataset', |
|||
method:'get_query_result', |
|||
}).then(val => { |
|||
this.FinalData.ForecastData = val |
|||
}); |
|||
const { p10, p50, p90 } = this.FinalData.ForecastData |
|||
function getMonthNameFromDate(dateString) { |
|||
const date = new Date(dateString); |
|||
const monthName = date.toLocaleString('default', { month: 'long' }); |
|||
return monthName; |
|||
} |
|||
const userDate = p10[0].Timestamp; |
|||
const monthName = getMonthNameFromDate(userDate); |
|||
let scatterChart = this.forecastBarGraph.el |
|||
new Chart(scatterChart, { |
|||
type: 'scatter', |
|||
data: { |
|||
datasets: [{ |
|||
label: 'Forecast in '+ monthName, |
|||
data: [ |
|||
{ 'date': p10[0].Timestamp, 'demand': p10[0].Value }, |
|||
{ 'date': p50[0].Timestamp, 'demand': p50[0].Value}, |
|||
{ 'date': p90[0].Timestamp, 'demand': p90[0].Value} |
|||
], |
|||
borderColor: 'rgb(0, 0, 255)', |
|||
backgroundColor: 'rgba(0, 0, 255, 0.5)' |
|||
}] |
|||
}, |
|||
options: { |
|||
parsing: { |
|||
xAxisKey: 'date', |
|||
yAxisKey: 'demand' |
|||
}, |
|||
scales: { |
|||
y: { |
|||
ticks: { |
|||
stepSize: 1 |
|||
} |
|||
}, |
|||
x: { |
|||
type: 'time', |
|||
time: { |
|||
unit: 'day', |
|||
}, |
|||
ticks: { |
|||
autoSkip: false, |
|||
stepSize: 1, |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
goBack() { |
|||
// this.trigger('back');
|
|||
browser.history.go(-1) |
|||
|
|||
|
|||
} |
|||
} |
|||
ForecastReport.template = "ForecastReport" |
|||
actionRegistry.add('forecast', ForecastReport); |
@ -0,0 +1,27 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<!-- QWeb Template for forecast graphical view--> |
|||
<templates id="template" xml:space="preserve"> |
|||
<t t-name="ForecastReport" owl="1"> |
|||
<div> |
|||
<center> |
|||
<h1> |
|||
Forecast Report |
|||
</h1> |
|||
</center> |
|||
</div> |
|||
<button class="btn btn-primary" t-on-click="goBack">Go Back</button> |
|||
<br/><br/> |
|||
<div class="col-md-5" style="margin-left: 20px;"> |
|||
<div class="shadow-lg p-3 mb-5 bg-white rounded" |
|||
style="height: 700px; width: 1000px;"> |
|||
<h2>Forecast Result</h2> |
|||
<span>X axis: Demand</span> |
|||
<span> Y Axis: Date</span> |
|||
<hr/> |
|||
<div class="bar"> |
|||
<canvas id="bubbleChart" t-ref="bubble-chart"/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
</templates> |
@ -0,0 +1,40 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!--Tree view of Amazon Bucket lists--> |
|||
<record id="amazon_bucket_view_tree" model="ir.ui.view"> |
|||
<field name="name">amazon.bucket.view.tree</field> |
|||
<field name="model">amazon.bucket</field> |
|||
<field name="arch" type="xml"> |
|||
<tree> |
|||
<field name="bucket_name"/> |
|||
</tree> |
|||
</field> |
|||
</record> |
|||
<!--Form View of Amazon Bucket--> |
|||
<record id="amazon_bucket_view_form" model="ir.ui.view"> |
|||
<field name="name">amazon.bucket.view.form</field> |
|||
<field name="model">amazon.bucket</field> |
|||
<field name="arch" type="xml"> |
|||
<form> |
|||
<header> |
|||
<button name="action_s3bucket" string="Create Bucket" type="object" class="oe_highlight"/> |
|||
<button name="action_s3bucket_push" string="Push To Bucket" type="object" class="oe_highlight"/> |
|||
<field name="state" widget="statusbar"/> |
|||
</header> |
|||
<sheet> |
|||
<group> |
|||
<field name="bucket_name"/> |
|||
<field name="file_path" attrs="{'invisible': [('state', 'in', ('create_bucket'))]}"/> |
|||
<field name="s3_uri" attrs="{'invisible': [('state', 'in', ('create_bucket', 'push_bucket'))]}"/> |
|||
</group> |
|||
</sheet> |
|||
</form> |
|||
</field> |
|||
</record> |
|||
<!--Window action amazon bucket creation--> |
|||
<record id="action_amazon_bucket" model="ir.actions.act_window"> |
|||
<field name="name">Bucket</field> |
|||
<field name="res_model">amazon.bucket</field> |
|||
<field name="view_mode">tree,form</field> |
|||
</record> |
|||
</odoo> |
@ -0,0 +1,66 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!--Tree view of amazon dataset for amazon forecasting--> |
|||
<record id="amazon_dataset_view_tree" model="ir.ui.view"> |
|||
<field name="name">amazon.dataset.view.tree</field> |
|||
<field name="model">amazon.dataset</field> |
|||
<field name="arch" type="xml"> |
|||
<tree> |
|||
<field name="role_name"/> |
|||
</tree> |
|||
</field> |
|||
</record> |
|||
<!--Form view of amazon dataset for amazon forecasting--> |
|||
<record id="amazon_dataset_view_form" model="ir.ui.view"> |
|||
<field name="name">amazon.dataset.view.form</field> |
|||
<field name="model">amazon.dataset</field> |
|||
<field name="arch" type="xml"> |
|||
<form> |
|||
<header> |
|||
<button name="action_create_table" string="Create Table" type="object" states="table" class="oe_highlight"/> |
|||
<button name="action_create_role" string="Create Role" type="object" states="role" class="oe_highlight"/> |
|||
<button name="action_create_kms" string="Create KMS" type="object" states="kms" class="oe_highlight"/> |
|||
<button name="action_create_policy" string="Create Policy" type="object" states="policy" class="oe_highlight"/> |
|||
<button name="action_create_dataset" string="Create Dataset" type="object" states="dataset" class="oe_highlight"/> |
|||
<button name="action_import_dataset" string="Import Dataset Job" type="object" states="import_dataset" class="oe_highlight"/> |
|||
<button name="action_create_predictor" string="Create Predictor" type="object" class="oe_highlight"/> |
|||
<button name="action_create_forecast" string="Create Forecast" type="object" class="oe_highlight"/> |
|||
<button name="query_forecast" string="Query Forecast" type="object" class="oe_highlight"/> |
|||
<field name="state" widget="statusbar" statusbar_visible="table,import_dataset,query_forecast"/> |
|||
</header> |
|||
<sheet> |
|||
<group> |
|||
<field name="table_name" /> |
|||
<field name="table_arn" /> |
|||
<field name="role_name" attrs="{'invisible': [('state', 'in', ('table'))], 'required': [('state', 'not in', ('table'))]}"/> |
|||
<field name="role_arn" attrs="{'invisible': [('state', 'in', ('table'))]}"/> |
|||
<field name="bucket_id" attrs="{'invisible': [('state', 'in', ('table', 'role'))], 'required': [('state', 'not in', ('table', 'role'))]}"/> |
|||
<field name="kms_alias" attrs="{'invisible': [('state', 'in', ('table', 'role'))], 'required': [('state', 'not in', ('table', 'role'))]}"/> |
|||
<field name="kms_arn" attrs="{'invisible': [('state', 'in', ('table', 'role'))]}"/> |
|||
<field name="policy_name" attrs="{'invisible': [('state', 'in', ('table', 'role', 'kms'))], 'required': [('state', 'not in', ('table', 'role', 'kms'))]}"/> |
|||
<field name="policy_arn" attrs="{'invisible': [('state', 'in', ('table', 'role', 'kms'))]}"/> |
|||
<field name="dataset_group" attrs="{'invisible': [('state', 'in', ('table', 'role', 'kms', 'policy'))], 'required': [('state', 'not in', ('table', 'role', 'kms', 'policy'))]}"/> |
|||
<field name="dataset_group_arn" attrs="{'invisible': [('state', 'in', ('table', 'role', 'kms', 'policy','dataset'))]}"/> |
|||
<field name="dataset" attrs="{'invisible': [('state', 'in', ('table', 'role', 'kms', 'policy'))], 'required': [('state', 'not in', ('table', 'role', 'kms', 'policy'))]}"/> |
|||
<field name="dataset_arn" attrs="{'invisible': [('state', 'in', ('table', 'role', 'kms', 'policy','dataset'))]}"/> |
|||
<field name="forecast_frequency" attrs="{'invisible': [('state', 'in', ('table', 'role', 'kms', 'policy'))]}"/> |
|||
<field name="import_job_name" attrs="{'invisible': [('state', 'in', ('table', 'role', 'kms', 'policy', 'dataset'))]}"/> |
|||
<field name="import_job_arn" attrs="{'invisible': [('state', 'in', ('table', 'role', 'kms', 'policy', 'dataset'))]}"/> |
|||
<field name="predictor_name" attrs="{'invisible': ['|', ('state', 'in', ('table', 'role', 'kms', 'policy', 'dataset')),('import_job_arn', '=', False)]}"/> |
|||
<field name="predictor_algorithm" attrs="{'invisible': ['|', ('state', 'in', ('table', 'role', 'kms', 'policy', 'dataset')), ('import_job_arn', '=', False)]}"/> |
|||
<field name="predictor_arn" attrs="{'invisible': ['|', ('state', 'in', ('table', 'role', 'kms', 'policy', 'dataset')), ('import_job_arn', '=', False)]}"/> |
|||
<field name="forecast_name" attrs="{'invisible': [('state', 'in', ('table', 'role', 'kms', 'policy', 'dataset', 'import_dataset'))], 'required': [('state', 'not in', ('table', 'role', 'kms', 'policy', 'dataset', 'import_dataset'))]}"/> |
|||
<field name="item_id" attrs="{'invisible': [('state', 'in', ('table', 'role', 'kms', 'policy', 'dataset', 'import_dataset', 'predictor'))], 'required': [('state', 'not in', ('table', 'role', 'kms', 'policy', 'dataset', 'import_dataset', 'predictor'))]}"/> |
|||
<field name="forecast_arn" attrs="{'invisible': [('state', 'in', ('table', 'role', 'kms', 'policy', 'dataset', 'import_dataset', 'predictor'))]}"/> |
|||
</group> |
|||
</sheet> |
|||
</form> |
|||
</field> |
|||
</record> |
|||
<!--Window action for Amazon Dataset --> |
|||
<record id="action_amazon_dataset" model="ir.actions.act_window"> |
|||
<field name="name">Forecast</field> |
|||
<field name="res_model">amazon.dataset</field> |
|||
<field name="view_mode">tree,form</field> |
|||
</record> |
|||
</odoo> |
@ -0,0 +1,38 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!--Tree view for fetching data from database--> |
|||
<record id="fetch_data_view_tree" model="ir.ui.view"> |
|||
<field name="name">amazon.fetch.data.view.tree</field> |
|||
<field name="model">amazon.fetch.data</field> |
|||
<field name="arch" type="xml"> |
|||
<tree> |
|||
<field name="db_name"/> |
|||
</tree> |
|||
</field> |
|||
</record> |
|||
<!--Form view for fetching data from database--> |
|||
<record id="fetch_data_view_form" model="ir.ui.view"> |
|||
<field name="name">amazon.fetch.data.view.form</field> |
|||
<field name="model">amazon.fetch.data</field> |
|||
<field name="arch" type="xml"> |
|||
<form> |
|||
<sheet> |
|||
<group> |
|||
<field name="url"/> |
|||
<field name="db_name"/> |
|||
<field name="db_username"/> |
|||
<field name="db_password" password="True"/> |
|||
<field name="csv_file_path"/> |
|||
<button name="action_fetch_data" string="Fetch Data" type="object" class="oe_highlight"/> |
|||
</group> |
|||
</sheet> |
|||
</form> |
|||
</field> |
|||
</record> |
|||
<!--Window Action of amazon fetch data--> |
|||
<record id="action_amazon_fetch_data" model="ir.actions.act_window"> |
|||
<field name="name">Fetch Data</field> |
|||
<field name="res_model">amazon.fetch.data</field> |
|||
<field name="view_mode">tree,form</field> |
|||
</record> |
|||
</odoo> |
@ -0,0 +1,20 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!--Menu items for Amazon forecasting operations--> |
|||
<menuitem id="menu_stock_forecast" |
|||
name="Amazon Forecast" |
|||
parent="stock.menu_stock_root" |
|||
sequence="15"/> |
|||
<menuitem id="menu_dynamodb" |
|||
action="action_amazon_dataset" |
|||
parent="menu_stock_forecast" |
|||
sequence="11"/> |
|||
<menuitem id="menu_s3bucket" |
|||
action="action_amazon_bucket" |
|||
parent="menu_stock_forecast" |
|||
sequence="15"/> |
|||
<menuitem id="menu_fetch_data" |
|||
action="action_amazon_fetch_data" |
|||
parent="menu_stock_forecast" |
|||
sequence="14"/> |
|||
</odoo> |
@ -0,0 +1,63 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<!--Form view for adding field for the authentication with AWS--> |
|||
<record id="res_config_settings_view_form" model="ir.ui.view"> |
|||
<field name="name"> |
|||
res.config.settings.view.form.inherit.amazon.forecast.integration |
|||
</field> |
|||
<field name="model">res.config.settings</field> |
|||
<field name="inherit_id" ref="stock.res_config_settings_view_form"/> |
|||
<field name="arch" type="xml"> |
|||
<div name="barcode_setting_container" position="after"> |
|||
<h2>Forecast</h2> |
|||
<div class="row mt16 o_settings_container" |
|||
name="forecast_setting_container"> |
|||
<div class="col-12 col-lg-6 o_setting_box" |
|||
id="forecast_process"> |
|||
<div class="o_setting_left_pane"> |
|||
<field name="amazon_forecast" widget="upgrade_boolean"/> |
|||
</div> |
|||
<div class="o_setting_right_pane" |
|||
id="forecast_settings"> |
|||
<label for="amazon_forecast"/> |
|||
<span class="fa fa-lg fa-building-o" |
|||
title="Values set here are company-specific." |
|||
groups="base.group_multi_company"/> |
|||
<div class="text-muted" name="stock_forecast"> |
|||
Forecast helps to predict stock and maintain |
|||
inventory correctly |
|||
</div> |
|||
<div class="content-group" |
|||
attrs="{'invisible': [('amazon_forecast','=',False)]}"> |
|||
<div class="mt16"> |
|||
<span class="col-lg-3">Access Key: |
|||
<field name="amazon_access_key" |
|||
attrs="{'required': [('amazon_forecast', '=', True)]}"/> |
|||
</span> |
|||
</div> |
|||
</div> |
|||
<div class="content-group" |
|||
attrs="{'invisible': [('amazon_forecast','=',False)]}"> |
|||
<div class="mt16"> |
|||
<span class="col-lg-3">Secret Access Key: |
|||
<field name="amazon_secret_access_key" password="True" |
|||
attrs="{'required': [('amazon_forecast', '=', True)]}"/> |
|||
</span> |
|||
</div> |
|||
</div> |
|||
<div class="content-group" |
|||
attrs="{'invisible': [('amazon_forecast','=',False)]}"> |
|||
<div class="mt16"> |
|||
<span class="col-lg-3">Region: |
|||
<field name="amazon_region" |
|||
attrs="{'required': [('amazon_forecast', '=', True)]}"/> |
|||
</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</field> |
|||
</record> |
|||
</odoo> |