Skip to content

Commit

Permalink
Odoo 12 and Python3 port
Browse files Browse the repository at this point in the history
* [ADD] Check route to have a response on working code

* [FIX] timesheet create on Odoo 12.0 models

* [IMP] Token generation based on python3

* [IMP] Create timesheet for specific user

* [REF] Refactoring user information

Odoo crypt password now so every time we try to get it, we have an empty string. With old code every user password would have been overwritten. With this refactoring we use an admin/manager account to write data for other users but force on creation the right user reference.

* [ADD] README and sample setting file

Co-authored-by: Apruzzese Francesco <cescoap@gmail.com>
  • Loading branch information
rasky and OpenCode committed Jan 7, 2020
1 parent 6e13039 commit 9c7c3d1
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 51 deletions.
36 changes: 36 additions & 0 deletions README.md
@@ -0,0 +1,36 @@
SENDTIME
========

Configuration
-------------

Create your configuration file. If you need you can use ```settings.cfg.sample``` file as template

Export configuration file path as environment data:

```
$ export SENDTIME_SETTINGS=/your/config/file/path
```

Run
---

Run **sendtime** as a python script


Test
----

It's possible to test **sendtime** with curl. For example:

### Check connection

```
$ curl http://127.0.0.1:5000/check
```

### Send data

```
$ curl --header "Content-Type: application/json" --request POST --data '{"date":"2019-01-30","description":"Descrizione di test","duration":120,"project":"Progetto di Test"}' http://127.0.0.1:5000/api/timesheet
```
89 changes: 38 additions & 51 deletions sendtime.py
Expand Up @@ -3,57 +3,38 @@

from flask import Flask, request, jsonify, abort
from werkzeug.contrib.cache import SimpleCache
import os
from secrets import token_hex
import erppeek
import time
import datetime
from calendar import monthrange


app = Flask(__name__)
app.config.from_envvar("SENDTIME_SETTINGS")
cache = SimpleCache()


def current_user():
def current_user(client):
user = request.environ.get('REMOTE_USER')
if user is None:
if app.config["DEBUG"] != 0:
user = "rasky"
else:
abort(400, {'error': 'REMOTE_USER not provided'})
# Retrieve odoo user id of this user
record = client.ResUsers.read([('login', '=', user)], fields=["id"])
if not record:
abort(400, {'error': 'This user does not exist in Odoo'})
return record[0]["id"]

# See if we have a client already in list
pwd = cache.get("pwd:" + user)
if pwd is None:
# Login as admin to retrieve userid and password for this user
# NOTE: Odoo saves passwords in clear... furtunately, we don't store
# the real passwords here (because we authenticate via SSO), but just
# a random-generated password.
client = odoo_client(
app.config["ODOO_USER"], app.config["ODOO_PASSWORD"])
record = client.ResUsers.read(
["login="+user], fields=["id", "password"])[0]

# Some users have no password
# (so login it's impossible with erppeek),
# or they have a manually generated password that we don't trust.
# Let's replace it.
if len(record["password"]) < 32:
newpwd = os.urandom(16).encode("hex")
client.ResUsers.write(record["id"], {"password": newpwd})
record["password"] = newpwd

cache.set("id:"+user, record["id"])
cache.set("pwd:"+user, record["password"])

return user, cache.get("id:"+user), cache.get("pwd:"+user)


def odoo_client(login, password):

def odoo_client():
return erppeek.Client(
app.config["ODOO_URI"],
app.config["ODOO_DB"],
login, password)
app.config["ODOO_USER"],
app.config["ODOO_PASSWORD"])


@app.errorhandler(500)
Expand All @@ -62,10 +43,15 @@ def server_error(e):
{"error": "internal server error", "exception": str(e)}), 500


@app.route('/check')
def check():
return jsonify({'message': 'It works!'})


@app.route('/api/timesheet', methods=["POST"])
def get_timesheet():
login, userid, pwd = current_user()
client = odoo_client(login, pwd)
client = odoo_client()
userid = current_user(client)

if request.json is None:
abort(400, {'error': 'request body not in JSON format'})
Expand Down Expand Up @@ -94,9 +80,9 @@ def get_timesheet():
abort(400, {'error': 'project not provided'})

# Extract project id from OpenERP (with unambiguous match)
pids = client.AccountAnalyticAccount.read(
["use_timesheets=True", "state=open", "name ilike " + proj],
fields=["name"])
pids = client.ProjectProject.read([('active', '=', True),
('name', 'ilike', proj), ],
fields=["name"])
if len(pids) == 0:
abort(400, {'error': 'no project found matching %s' % proj})
elif len(pids) > 1:
Expand All @@ -108,13 +94,16 @@ def get_timesheet():
projectid = pids[0]["id"]

# Search for a draft timesheet for this user
# NOTE: some timesheets are in state "draft_positive". Not sure what
# that means, but they must be matched here
sheetid = client.Hr_timesheet_sheetSheet.search(
["state like draft%",
"user_id=%d" % userid,
"date_from=%04d-%02d-01" % (date.year, date.month)],
)
sheetid = client.Hr_timesheetSheet.search([
('state', 'in', ('draft', 'new')),
('user_id', '=', userid),
('date_start', '>=', '%04d-%02d-01' % (date.year, date.month)),
('date_end', '<=', '%04d-%02d-%02d' % (
date.year,
date.month,
monthrange(date.year, date.month)[1],
))
])
if len(sheetid) == 0:
abort(
400,
Expand All @@ -125,14 +114,12 @@ def get_timesheet():
sheetid = sheetid[0]

# Now create a registration
newrecord = client.HrAnalyticTimesheet.create({
"journal_id": 6, # Hard-coded timesheet journal used by Develer
"account_id": projectid,
"sheet_id": sheetid,
"date": date.strftime("%Y-%m-%d"),
"unit_amount": float(minutes)/60,
"user_id": userid,
"name": desc,
newrecord = client.AccountAnalyticLine.create({
'date': date.strftime('%Y-%m-%d'),
'project_id': projectid,
'name': desc,
'unit_amount': float(minutes)/60,
'user_id': userid,
})

return jsonify({
Expand Down
6 changes: 6 additions & 0 deletions settings.cfg.sample
@@ -0,0 +1,6 @@
DEBUG = True
SECRET_KEY = b'YOUR_KEY_HERE'
ODOO_USER = 'admin'
ODOO_PASSWORD = 'admin'
ODOO_URI = 'http://localhost:8069'
ODOO_DB = 'demo'

0 comments on commit 9c7c3d1

Please sign in to comment.