Browse Source

APR 20: [ADD] Initial Commit 'amazon_forecast_integration'

pull/278/merge
Shijin V 1 year ago
parent
commit
6673301700
  1. 53
      amazon_forecast_integration/README.rst
  2. 22
      amazon_forecast_integration/__init__.py
  3. 60
      amazon_forecast_integration/__manifest__.py
  4. 7
      amazon_forecast_integration/doc/RELEASE_NOTES.md
  5. 25
      amazon_forecast_integration/models/__init__.py
  6. 136
      amazon_forecast_integration/models/amazon_bucket.py
  7. 602
      amazon_forecast_integration/models/amazon_dataset.py
  8. 86
      amazon_forecast_integration/models/amazon_fetch_data.py
  9. 77
      amazon_forecast_integration/models/res_config_settings.py
  10. 4
      amazon_forecast_integration/security/ir.model.access.csv
  11. BIN
      amazon_forecast_integration/static/description/assets/icons/check.png
  12. BIN
      amazon_forecast_integration/static/description/assets/icons/chevron.png
  13. BIN
      amazon_forecast_integration/static/description/assets/icons/cogs.png
  14. BIN
      amazon_forecast_integration/static/description/assets/icons/consultation.png
  15. BIN
      amazon_forecast_integration/static/description/assets/icons/ecom-black.png
  16. BIN
      amazon_forecast_integration/static/description/assets/icons/education-black.png
  17. BIN
      amazon_forecast_integration/static/description/assets/icons/hotel-black.png
  18. BIN
      amazon_forecast_integration/static/description/assets/icons/license.png
  19. BIN
      amazon_forecast_integration/static/description/assets/icons/lifebuoy.png
  20. BIN
      amazon_forecast_integration/static/description/assets/icons/manufacturing-black.png
  21. BIN
      amazon_forecast_integration/static/description/assets/icons/pos-black.png
  22. BIN
      amazon_forecast_integration/static/description/assets/icons/puzzle.png
  23. BIN
      amazon_forecast_integration/static/description/assets/icons/restaurant-black.png
  24. BIN
      amazon_forecast_integration/static/description/assets/icons/service-black.png
  25. BIN
      amazon_forecast_integration/static/description/assets/icons/trading-black.png
  26. BIN
      amazon_forecast_integration/static/description/assets/icons/training.png
  27. BIN
      amazon_forecast_integration/static/description/assets/icons/update.png
  28. BIN
      amazon_forecast_integration/static/description/assets/icons/user.png
  29. BIN
      amazon_forecast_integration/static/description/assets/icons/wrench.png
  30. BIN
      amazon_forecast_integration/static/description/assets/misc/categories.png
  31. BIN
      amazon_forecast_integration/static/description/assets/misc/check-box.png
  32. BIN
      amazon_forecast_integration/static/description/assets/misc/compass.png
  33. BIN
      amazon_forecast_integration/static/description/assets/misc/corporate.png
  34. BIN
      amazon_forecast_integration/static/description/assets/misc/customer-support.png
  35. BIN
      amazon_forecast_integration/static/description/assets/misc/cybrosys-logo.png
  36. BIN
      amazon_forecast_integration/static/description/assets/misc/features.png
  37. BIN
      amazon_forecast_integration/static/description/assets/misc/logo.png
  38. BIN
      amazon_forecast_integration/static/description/assets/misc/pictures.png
  39. BIN
      amazon_forecast_integration/static/description/assets/misc/pie-chart.png
  40. BIN
      amazon_forecast_integration/static/description/assets/misc/right-arrow.png
  41. BIN
      amazon_forecast_integration/static/description/assets/misc/star.png
  42. BIN
      amazon_forecast_integration/static/description/assets/misc/support.png
  43. BIN
      amazon_forecast_integration/static/description/assets/misc/whatsapp.png
  44. BIN
      amazon_forecast_integration/static/description/assets/modules/1.jpg
  45. BIN
      amazon_forecast_integration/static/description/assets/modules/2.png
  46. BIN
      amazon_forecast_integration/static/description/assets/modules/3.png
  47. BIN
      amazon_forecast_integration/static/description/assets/modules/4.png
  48. BIN
      amazon_forecast_integration/static/description/assets/modules/5.png
  49. BIN
      amazon_forecast_integration/static/description/assets/modules/6.png
  50. BIN
      amazon_forecast_integration/static/description/assets/screenshots/forecast-01.png
  51. BIN
      amazon_forecast_integration/static/description/assets/screenshots/forecast-02.png
  52. BIN
      amazon_forecast_integration/static/description/assets/screenshots/forecast-03.png
  53. BIN
      amazon_forecast_integration/static/description/assets/screenshots/forecast-04.png
  54. BIN
      amazon_forecast_integration/static/description/assets/screenshots/forecast-05.png
  55. BIN
      amazon_forecast_integration/static/description/assets/screenshots/forecast-06.png
  56. BIN
      amazon_forecast_integration/static/description/assets/screenshots/forecast-07.png
  57. BIN
      amazon_forecast_integration/static/description/assets/screenshots/forecast-08.png
  58. BIN
      amazon_forecast_integration/static/description/assets/screenshots/forecast-09.png
  59. BIN
      amazon_forecast_integration/static/description/assets/screenshots/forecast-10.png
  60. BIN
      amazon_forecast_integration/static/description/assets/screenshots/forecast-11.png
  61. BIN
      amazon_forecast_integration/static/description/assets/screenshots/forecast-12.png
  62. BIN
      amazon_forecast_integration/static/description/assets/screenshots/forecast-13.png
  63. BIN
      amazon_forecast_integration/static/description/assets/screenshots/forecast-14.png
  64. BIN
      amazon_forecast_integration/static/description/assets/screenshots/forecast-15.png
  65. BIN
      amazon_forecast_integration/static/description/assets/screenshots/forecast-16.png
  66. BIN
      amazon_forecast_integration/static/description/assets/screenshots/forecast-17.png
  67. BIN
      amazon_forecast_integration/static/description/assets/screenshots/forecast.gif
  68. BIN
      amazon_forecast_integration/static/description/banner.jpg
  69. BIN
      amazon_forecast_integration/static/description/icon.png
  70. 657
      amazon_forecast_integration/static/description/index.html
  71. 97
      amazon_forecast_integration/static/src/js/graphView.js
  72. 27
      amazon_forecast_integration/static/src/xml/graph_view.xml
  73. 40
      amazon_forecast_integration/views/amazon_bucket_views.xml
  74. 66
      amazon_forecast_integration/views/amazon_dataset_views.xml
  75. 38
      amazon_forecast_integration/views/amazon_fetch_data_views.xml
  76. 20
      amazon_forecast_integration/views/menus.xml
  77. 63
      amazon_forecast_integration/views/res_config_settings_views.xml

53
amazon_forecast_integration/README.rst

@ -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>`__

22
amazon_forecast_integration/__init__.py

@ -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

60
amazon_forecast_integration/__manifest__.py

@ -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,
}

7
amazon_forecast_integration/doc/RELEASE_NOTES.md

@ -0,0 +1,7 @@
## Module <amazon_forecast_integration>
#### 20.04.2024
#### Version 16.0.1.0.0
#### ADD
- Initial Commit for Amazon Forecast Integration

25
amazon_forecast_integration/models/__init__.py

@ -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

136
amazon_forecast_integration/models/amazon_bucket.py

@ -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"})

602
amazon_forecast_integration/models/amazon_dataset.py

@ -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

86
amazon_forecast_integration/models/amazon_fetch_data.py

@ -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

77
amazon_forecast_integration/models/res_config_settings.py

@ -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 '')

4
amazon_forecast_integration/security/ir.model.access.csv

@ -0,0 +1,4 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_amazon_dataset,access.amazon.dataset,model_amazon_dataset,base.group_user,1,1,1,1
access_amazon_bucket,access.amazon.bucket,model_amazon_bucket,base.group_user,1,1,1,1
access_amazon_fetch_data,access.amazon.fetch.data,model_amazon_fetch_data,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_amazon_dataset access.amazon.dataset model_amazon_dataset base.group_user 1 1 1 1
3 access_amazon_bucket access.amazon.bucket model_amazon_bucket base.group_user 1 1 1 1
4 access_amazon_fetch_data access.amazon.fetch.data model_amazon_fetch_data base.group_user 1 1 1 1

BIN
amazon_forecast_integration/static/description/assets/icons/check.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
amazon_forecast_integration/static/description/assets/icons/chevron.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

BIN
amazon_forecast_integration/static/description/assets/icons/cogs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
amazon_forecast_integration/static/description/assets/icons/consultation.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
amazon_forecast_integration/static/description/assets/icons/ecom-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

BIN
amazon_forecast_integration/static/description/assets/icons/education-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

BIN
amazon_forecast_integration/static/description/assets/icons/hotel-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

BIN
amazon_forecast_integration/static/description/assets/icons/license.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
amazon_forecast_integration/static/description/assets/icons/lifebuoy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
amazon_forecast_integration/static/description/assets/icons/manufacturing-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

BIN
amazon_forecast_integration/static/description/assets/icons/pos-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

BIN
amazon_forecast_integration/static/description/assets/icons/puzzle.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

BIN
amazon_forecast_integration/static/description/assets/icons/restaurant-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

BIN
amazon_forecast_integration/static/description/assets/icons/service-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

BIN
amazon_forecast_integration/static/description/assets/icons/trading-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

BIN
amazon_forecast_integration/static/description/assets/icons/training.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

BIN
amazon_forecast_integration/static/description/assets/icons/update.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
amazon_forecast_integration/static/description/assets/icons/user.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

BIN
amazon_forecast_integration/static/description/assets/icons/wrench.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
amazon_forecast_integration/static/description/assets/misc/categories.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
amazon_forecast_integration/static/description/assets/misc/check-box.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
amazon_forecast_integration/static/description/assets/misc/compass.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
amazon_forecast_integration/static/description/assets/misc/corporate.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
amazon_forecast_integration/static/description/assets/misc/customer-support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
amazon_forecast_integration/static/description/assets/misc/cybrosys-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
amazon_forecast_integration/static/description/assets/misc/features.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

BIN
amazon_forecast_integration/static/description/assets/misc/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
amazon_forecast_integration/static/description/assets/misc/pictures.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
amazon_forecast_integration/static/description/assets/misc/pie-chart.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
amazon_forecast_integration/static/description/assets/misc/right-arrow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

BIN
amazon_forecast_integration/static/description/assets/misc/star.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
amazon_forecast_integration/static/description/assets/misc/support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
amazon_forecast_integration/static/description/assets/misc/whatsapp.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
amazon_forecast_integration/static/description/assets/modules/1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

BIN
amazon_forecast_integration/static/description/assets/modules/2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

BIN
amazon_forecast_integration/static/description/assets/modules/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

BIN
amazon_forecast_integration/static/description/assets/modules/4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
amazon_forecast_integration/static/description/assets/modules/5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
amazon_forecast_integration/static/description/assets/modules/6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
amazon_forecast_integration/static/description/assets/screenshots/forecast-01.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

BIN
amazon_forecast_integration/static/description/assets/screenshots/forecast-02.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

BIN
amazon_forecast_integration/static/description/assets/screenshots/forecast-03.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

BIN
amazon_forecast_integration/static/description/assets/screenshots/forecast-04.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
amazon_forecast_integration/static/description/assets/screenshots/forecast-05.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
amazon_forecast_integration/static/description/assets/screenshots/forecast-06.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
amazon_forecast_integration/static/description/assets/screenshots/forecast-07.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
amazon_forecast_integration/static/description/assets/screenshots/forecast-08.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
amazon_forecast_integration/static/description/assets/screenshots/forecast-09.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
amazon_forecast_integration/static/description/assets/screenshots/forecast-10.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
amazon_forecast_integration/static/description/assets/screenshots/forecast-11.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

BIN
amazon_forecast_integration/static/description/assets/screenshots/forecast-12.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

BIN
amazon_forecast_integration/static/description/assets/screenshots/forecast-13.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

BIN
amazon_forecast_integration/static/description/assets/screenshots/forecast-14.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

BIN
amazon_forecast_integration/static/description/assets/screenshots/forecast-15.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

BIN
amazon_forecast_integration/static/description/assets/screenshots/forecast-16.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

BIN
amazon_forecast_integration/static/description/assets/screenshots/forecast-17.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

BIN
amazon_forecast_integration/static/description/assets/screenshots/forecast.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 KiB

BIN
amazon_forecast_integration/static/description/banner.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

BIN
amazon_forecast_integration/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

657
amazon_forecast_integration/static/description/index.html

@ -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 &amp; 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 -->

97
amazon_forecast_integration/static/src/js/graphView.js

@ -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);

27
amazon_forecast_integration/static/src/xml/graph_view.xml

@ -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>

40
amazon_forecast_integration/views/amazon_bucket_views.xml

@ -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>

66
amazon_forecast_integration/views/amazon_dataset_views.xml

@ -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>

38
amazon_forecast_integration/views/amazon_fetch_data_views.xml

@ -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>

20
amazon_forecast_integration/views/menus.xml

@ -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>

63
amazon_forecast_integration/views/res_config_settings_views.xml

@ -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>
Loading…
Cancel
Save