diff --git a/README.rst b/README.rst
index 786b31a853d3471cb220b09011b8c88fec7af269..ae6b9aec7e6070ba8aa3d5ba6d11fff72a0f8688 100644
--- a/README.rst
+++ b/README.rst
@@ -3,9 +3,9 @@
    :alt: License: AGPL-3
 
 
-===========
+============================
 OACC - Clefs de répartition
-===========
+============================
 
 Ce module permet d'uploader de tester et d envoyer a enedis les clefs de répartion pour une Opération d'AutoConsommation Collective:
 
diff --git a/__init__.py b/__init__.py
index 0650744f6bc69b9f0b865e8c7174c813a5f5995e..9b4296142f475392fb090e036775e999aa8e4a27 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1 +1,2 @@
 from . import models
+from . import wizard
diff --git a/__manifest__.py b/__manifest__.py
index 7fe41215d73add1783772a5f15f67759dc84d2e9..6acd5147f36b7772869334f4a4adacaaa931782b 100644
--- a/__manifest__.py
+++ b/__manifest__.py
@@ -11,9 +11,11 @@
         # datas
         # views
         "views/acc_operation_views.xml",
+        "views/acc_repartition_keys_views.xml",
         # views menu
         # wizard
+        "wizard/acc_repartition_keys_wizard_views.xml",
     ],
     "installable": True,
     "auto_install": False,
-}
\ No newline at end of file
+}
diff --git a/models/__init__.py b/models/__init__.py
index 95d38c215ba89c65cad06e91e331a0c07c964034..183168978d7da2e5bc4b899455e45738c23fa71c 100644
--- a/models/__init__.py
+++ b/models/__init__.py
@@ -1,2 +1,2 @@
 from . import acc_operation
-from . import acc_repartition_keys
\ No newline at end of file
+from . import acc_repartition_keys
diff --git a/models/acc_operation.py b/models/acc_operation.py
index fd774d86a6d9648b8a1b8f44317a7f57d7373e43..1d29e8b9847a79b0931a55fdf70b7abc905206ac 100644
--- a/models/acc_operation.py
+++ b/models/acc_operation.py
@@ -1,8 +1,8 @@
 # Copyright 2021- Le Filament (https://le-filament.com)
 # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
 import logging
-from odoo import _, fields, models
 
+from odoo import fields, models
 
 _logger = logging.getLogger(__name__)
 
@@ -41,4 +41,4 @@ class AccOperation(models.Model):
 
     # ------------------------------------------------------
     # Actions
-    # ------------------------------------------------------
\ No newline at end of file
+    # ------------------------------------------------------
diff --git a/models/acc_repartition_keys.py b/models/acc_repartition_keys.py
index b71474b6dc6bee9dae6caebb8ab0ddffc6f63120..c71adcb01b9019c664f529ed4b20cd75c6a9bff5 100644
--- a/models/acc_repartition_keys.py
+++ b/models/acc_repartition_keys.py
@@ -38,4 +38,4 @@ class AccRepartitionKeys(models.Model):
 
     # ------------------------------------------------------
     # Business methods
-    # ------------------------------------------------------
\ No newline at end of file
+    # ------------------------------------------------------
diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv
index a07c238c3c4e011114332311e63bb8eab958fd89..8ce08fbf566180e8a2427a4909f4f8e185dee91f 100644
--- a/security/ir.model.access.csv
+++ b/security/ir.model.access.csv
@@ -1,3 +1,4 @@
 id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
 "access_acc_repartition_keys_group_partner_manager","acc_repartition_keys group_partner_manager","model_acc_repartition_keys","base.group_partner_manager",1,1,1,1
-"access_acc_repartition_keys_group_user","acc_repartition_keys group_user","model_acc_repartition_keys","base.group_user",1,0,0,0
\ No newline at end of file
+"access_acc_repartition_keys_group_user","acc_repartition_keys group_user","model_acc_repartition_keys","base.group_user",1,0,0,0
+"access_acc_repartition_keys_wizard_group_partner_manager","acc_repartition_keys_wizard group_partner_manager","model_acc_repartition_keys_wizard","base.group_partner_manager",1,1,1,1
diff --git a/static/description/icon.png b/static/description/icon.png
new file mode 100755
index 0000000000000000000000000000000000000000..82ef47760a441cf229b5009f0a18ccf3842fbfa5
Binary files /dev/null and b/static/description/icon.png differ
diff --git a/tools/__init__.py b/tools/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tools/key_file.py b/tools/key_file.py
new file mode 100644
index 0000000000000000000000000000000000000000..7e8a0a7feff78ea413a4d4eccc9ebf58b88ff50d
--- /dev/null
+++ b/tools/key_file.py
@@ -0,0 +1,149 @@
+"""
+Repartion key entry file handler
+"""
+import csv
+from datetime import datetime
+
+
+class RepartitionKeyEntryFile:
+    def __init__(self, data, operation_counter_list):
+        self.data = data
+        self.operation_counter_list = operation_counter_list
+        self.json = self._to_json()
+
+    def check(self):
+        """
+        Lorsque le fichier est validé, des vérifications sont effectuées, et une erreur est affichée si le test ne passe pas :
+            • Première ligne, colonnes 2 à la fin : les numéros de PRM sont exactement ceux qui sont dans l’onglet Point de soutirage.
+             Aucun numéro de PRM n'apparaît plusieurs fois.
+        ◦ Erreur envoyée : “Les numéros de PRM ne correspondent pas à ceux de l’opération.”
+
+            • Lignes 2 à la fin, Horodate : Les dates sont celles d’un seul mois complet.
+        ◦ Erreur envoyée “Les dates doivent être celles d’un seul mois complet.”
+
+            • La somme sur chaque ligne doit être inférieure à 100.
+        ◦ Erreur envoyée “Ligne X : la somme dépasse 100%”
+
+        """
+        check_methods = [self._check_counter, self._check_same_month, self._check_max_value]
+        result = {"check": True, "message": ""}
+        for check in check_methods:
+            check_result = check()
+            if not check_result.get("check"):
+                result["check"] = False
+                result["message"] += f"{check_result['message']}\n"
+
+        return result
+
+    def _to_json(self):
+        """
+        make data ready to send { "horodatage": [{"id": "value"}, ....]}
+        """
+        json = {}
+        counter_list_from_file = self.data[0].split(";")
+        csv_file = csv.reader(self.data, delimiter=";")
+        line_count = 0
+        for line in csv_file:
+            if line:
+                if line_count == 0:
+                    line_count += 1
+                    continue
+                json[line[0]] = []
+                line_count += 1
+                counter_count = 1
+                for counter in counter_list_from_file[1:]:
+                    json[line[0]].append(
+                        {"id": counter, "key": line[counter_count].replace(",", ".")}
+                    )
+                    counter_count += 1
+        return json
+
+    def data_to_send(self, agreement_id, send_empty_key=False):
+        """
+        return dict {"route", "body} to enedis
+        """
+        call_list = []
+        for horo in self.json:
+            date = datetime.strptime(horo, "%d-%m-%Y %H:%M")
+            route = f"/agreements/{agreement_id}/repartition_keys/{date.strftime('%Y%m%dT%H%MZ')}"
+            body = []
+            for keys in self.json.get(horo):
+                if send_empty_key:
+                    body.append(keys)
+                else:
+                    if float(keys.get("key")) > 0:
+                        body.append(keys)
+            if body:
+                call_list.append({"route": route, "body": body})
+        return call_list
+
+    def _check_counter(self):
+        """
+        Check if all counter in file belong to operation
+
+        """
+
+        if self.data:
+            counter_list_from_file = self.data[0].split(";")[1:]
+
+            if sorted(self.operation_counter_list) == sorted(counter_list_from_file):
+                return {"check": True, "message": ""}
+            else:
+                missing_in_file = [
+                    counter
+                    for counter in self.operation_counter_list
+                    if counter not in counter_list_from_file
+                ]
+                missing_in_operation = [
+                    counter
+                    for counter in counter_list_from_file
+                    if counter not in self.operation_counter_list
+                ]
+                if missing_in_file or missing_in_operation:
+                    return {
+                        "check": False,
+                        "message": "Les numéros de PRM ne correspondent pas à ceux de l’opération",
+                    }
+                return {"check": True, "message": ""}
+
+    def _check_max_value(self):
+        """
+        check if all value are in the same month
+        """
+        for hour in self.json:
+            max = 0
+            for key in self.json[hour]:
+                if key["key"] == "0.00000000":
+                    key["key"] = 0.0
+                try:
+                    max = max + float(key["key"])
+                except ValueError:
+                    pass
+
+            if max > 100:
+                return {
+                    "check": False,
+                    "message": f"Ligne {hour} la somme dépasse 100.",
+                }
+        return {"check": True, "message": ""}
+
+    def _check_same_month(self):
+        """
+        check if all value are in the same month
+        """
+        if (
+            len(
+                set(
+                    [
+                        datetime.strptime(date, "%d-%m-%Y %H:%M").month
+                        for date in self.json
+                    ]
+                )
+            )
+            != 1
+        ):
+            return {
+                "check": False,
+                "message": "Les dates doivent être celles d’un seul mois complet.",
+            }
+        return {"check": True, "message": ""}
diff --git a/views/acc_operation_views.xml b/views/acc_operation_views.xml
index f5b2aa50b103e97f0c1393d2692860a8c545fcc8..a70536fe13406258983dce017b7891cec2e4f79f 100644
--- a/views/acc_operation_views.xml
+++ b/views/acc_operation_views.xml
@@ -2,7 +2,6 @@
 <!-- Copyright 2021- Le Filament (https://le-filament.com)
      License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
 <odoo>
-
     <record id="acc_operation_form_view" model="ir.ui.view">
         <field name="name">acc_operation_form_view.keys.form</field>
         <field name="model">acc.operation</field>
@@ -11,22 +10,18 @@
             <xpath expr="//notebook" position="inside">
                 <page string="Clefs de répartition" name="keys">
                     <header>
-<!--                        <button-->
-<!--                            string="Test"-->
-<!--                            type="object"-->
-<!--                            class="btn-primary"-->
-<!--                            name="test_file"-->
-<!--                        />-->
+                        <button
+                            string="Importer un fichier"
+                            type="action"
+                            name="%(oacc_repartition_keys.acc_repartition_keys_wizard_action)d"
+                            class="btn-primary"
+                        />
                     </header>
-                    <group>
+                    <tree>
                         <field name="keys_repartition_ids" />
-<!--                            <tree>-->
-<!--                                <field name="date_send"/>-->
-<!--                            </tree>-->
-                    </group>
+                    </tree>
                 </page>
             </xpath>
         </field>
     </record>
-
 </odoo>
\ No newline at end of file
diff --git a/views/acc_repartition_keys_views.xml b/views/acc_repartition_keys_views.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e247914f5a22123da9b78669b55d7187c16f996f
--- /dev/null
+++ b/views/acc_repartition_keys_views.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+<!--    <data>-->
+        <record id="acc_keys_repatition_action" model="ir.actions.act_window">
+            <field name="name">Keys</field>
+            <field name="res_model">acc.repartition.keys</field>
+            <field name="view_mode">tree,form</field>
+        </record>
+        <record id="acc_keys_repartition_tree" model="ir.ui.view">
+            <field name="name">acc.repartition.keys.tree</field>
+            <field name="model">acc.repartition.keys</field>
+            <field name="arch" type="xml">
+                <tree string="Keys" editable="bottom">
+                    <field name="date_send"/>
+                    <field name="csv_file"/>
+                    <field name="operation_id"/>
+                </tree>
+            </field>
+        </record>
+<!--    </data>-->
+</odoo>
\ No newline at end of file
diff --git a/wizard/__init__.py b/wizard/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..cbd8c61e5e0dbd922961fa9b0b9117dc317a3bc3
--- /dev/null
+++ b/wizard/__init__.py
@@ -0,0 +1 @@
+from . import acc_repartition_keys_wizard
diff --git a/wizard/acc_repartition_keys_wizard.py b/wizard/acc_repartition_keys_wizard.py
new file mode 100644
index 0000000000000000000000000000000000000000..1d414ccdb6538b7365d853c5ede80999686d4da5
--- /dev/null
+++ b/wizard/acc_repartition_keys_wizard.py
@@ -0,0 +1,82 @@
+# Copyright 2021- Le Filament (https://le-filament.com)
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
+import base64
+from odoo import fields, models
+from odoo.exceptions import UserError
+
+from ..tools.key_file import RepartitionKeyEntryFile
+
+
+class AccRepartitionKeysWizard(models.TransientModel):
+    _name = "acc.repartition.keys.wizard"
+    _description = "Clefs de répartition"
+
+    # ------------------------------------------------------
+    # Default methods
+    # ------------------------------------------------------
+    def _default_operation_id(self):
+        return self.env.context.get("active_id")
+
+    # ------------------------------------------------------
+    # Fields declaration
+    # ------------------------------------------------------
+    csv_file = fields.Binary("Contenu du fichier CSV")
+    date_send = fields.Date("Date de l'envoi des clefs", default=None)
+    operation_id = fields.Many2one(
+        "acc.operation", "Opération", default=_default_operation_id
+    )
+
+    # ------------------------------------------------------
+    # SQL Constraints
+    # ------------------------------------------------------
+
+    # ------------------------------------------------------
+    # Computed fields / Search Fields
+    # ------------------------------------------------------
+
+    # ------------------------------------------------------
+    # Onchange / Constraints
+    # ------------------------------------------------------
+
+    # ------------------------------------------------------
+    # CRUD methods (ORM overrides)
+    # ------------------------------------------------------
+
+    # ------------------------------------------------------
+    # Actions
+    # ------------------------------------------------------
+    def send_imported_file(self):
+        """
+        testing a file, check taht all prm id exist, are in operation and all operation prm are in file
+        :return:
+        """
+        if self.csv_file:
+            file = (
+                base64.b64decode(self.csv_file)
+                .decode("utf-8")
+                .replace("\r", "")
+                .split("\n")
+            )
+
+            counter_list_from_operation = [
+                counter.name
+                for counter in self.env["acc.counter"].search(
+                    [("acc_operation_id.id", "=", self.operation_id.id)]
+                )
+            ]
+
+            entry_file_handler = RepartitionKeyEntryFile(
+                data=file, operation_counter_list=counter_list_from_operation
+            )
+
+            file_check_result = entry_file_handler.check()
+
+            if not file_check_result.get("check"):
+                raise UserError(file_check_result.get("message"))
+
+            data_to_send = entry_file_handler.data_to_send(agreement_id=self.operation_id.name)
+
+
+    # ------------------------------------------------------
+    # Business methods
+    # ------------------------------------------------------
diff --git a/wizard/acc_repartition_keys_wizard_views.xml b/wizard/acc_repartition_keys_wizard_views.xml
new file mode 100644
index 0000000000000000000000000000000000000000..77b21811042851c0ec169d05da5c7384f6f6485c
--- /dev/null
+++ b/wizard/acc_repartition_keys_wizard_views.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+    <record id="acc_repartition_keys_wizard_form" model="ir.ui.view">
+        <field name="name">acc.repartition.keys.wizard.form</field>
+        <field name="model">acc.repartition.keys.wizard</field>
+        <field name="arch" type="xml">
+            <form string="Création clefs de repartition">
+                <header>
+                     <button
+                        class="btn btn-primary"
+                        name="send_imported_file"
+                        type="object"
+                        string="Envoyer a enedis"
+                    />
+                </header>
+                <group name="keys" string="Clefs de repartition" col="2">
+                    <field name="csv_file"/>
+                </group>
+            </form>
+        </field>
+    </record>
+
+    <record id="acc_repartition_keys_wizard_action" model="ir.actions.act_window">
+        <field name="name">Création clefs de repartition</field>
+        <field name="type">ir.actions.act_window</field>
+        <field name="res_model">acc.repartition.keys.wizard</field>
+        <field name="view_mode">form</field>
+        <field
+            name="view_id"
+            ref="acc_repartition_keys_wizard_form"
+        />
+        <field name="target">new</field>
+    </record>
+</odoo>
\ No newline at end of file