# -*- coding: utf-8 -*-
"""
Created on Mon Apr 16 17:37:11 2018
@author: Charles Edmond TanYZ
Simple app to:
1. Log in to Limesurvey and get your key to perform operations
2. Find a select a csv to change emails
3. Change the emails
"""
#####
# for the csv, first column will be the "key", second column will be the "value"
#####

import Tkinter as tk
import urllib
import urllib2
import json
import sys
import csv
import os
import tkFileDialog

###############################################################################
###############################################################################

def get_session_key(user, pw):
    req = urllib2.Request(url='https://survey.inresearch.com.sg/index.php/admin/remotecontrol',\
                          data='{\"method\":\"get_session_key\",\"params\":[\"'+user+'\",\"'+pw+'\"],\"id\":1}')
    req.add_header('content-type', 'application/json')
    req.add_header('connection', 'Keep-Alive')
    try:
        f = urllib2.urlopen(req)
        myretun = f.read()
        #print myretun
        j=json.loads(myretun)
        return j['result']
    except :
        e = sys.exc_info()[0]
        print ( "
Error: %s
" % e )

def release_session_key(relkey):
    req = urllib2.Request(url='https://survey.inresearch.com.sg/index.php/admin/remotecontrol',\
                          data='{\"method\":\"release_session_key\",\"params\":[\"'+relkey+'\"],\"id\":1}')
    req.add_header('content-type', 'application/json')
    req.add_header('connection', 'Keep-Alive')
    try:
        f = urllib2.urlopen(req)
        myretun = f.read()
        #print myretun
        j=json.loads(myretun)
        return j['result']
    except :
        e = sys.exc_info()[0]
        print ( "
Error: %s
" % e )

def get_participant_email(skey, sid, tid):
    req = urllib2.Request(url='https://survey.inresearch.com.sg/index.php/admin/remotecontrol',\
                      data='{\"method\":\"get_participant_properties\",\
                              "params\":\
                              [\
                              "'+skey+'\",\
                              "'+sid+'\",\
                              "'+tid+'\",[\
                              "email\"]\
                              ],\
                              "id\": 1}')
    req.add_header('content-type', 'application/json')
    req.add_header('connection', 'Keep-Alive')
    try:
        f = urllib2.urlopen(req)
        myretun = f.read()
        #print myretun
        j=json.loads(myretun)
        return j['result']
    except:
        e = sys.exc_info()[0]
        print ( "
Error: %s
" % e )

def set_participant_email(skey, sid, tid, newEmail):
    req = urllib2.Request(url='https://survey.inresearch.com.sg/index.php/admin/remotecontrol',\
                      data='{\"method\":\"set_participant_properties\",\
                              "params\":[\
                                         "'+skey+'\",\
                                         "'+sid+'\",\
                                         "'+tid+'\",\
                                         {\
                                         "email\":\"'+newEmail+'\",\
                                         "sent\":\"N\",\
                                         "remindersent\":\"N\",\
                                         "remindercount\":\"0\"\
                                         }\
                                         ],\
                              "id\": 1}')
    req.add_header('content-type', 'application/json')
    req.add_header('connection', 'Keep-Alive')
    try:
        f = urllib2.urlopen(req)
        myretun = f.read()
        #print myretun
        j=json.loads(myretun)
        return j['result']
    except:
        e = sys.exc_info()[0]
        print ( "
Error: %s
" % e )

def list_surveys(skey, user):
    req = urllib2.Request(url='https://survey.inresearch.com.sg/index.php/admin/remotecontrol',\
                          data='{\"method\":\"list_surveys\",\"params\":[\"'+skey+'\",\"'+user+'\"],\"id\":1}')
    req.add_header('content-type', 'application/json')
    req.add_header('connection', 'Keep-Alive')
    try:
        f = urllib2.urlopen(req)
        myretun = f.read()
        #print myretun
        j=json.loads(myretun)
        return j['result']
    except :
        e = sys.exc_info()[0]
        print ( "
Error: %s
" % e )

#hard coded to list only up to 18000 participants
def list_participants(skey, sid):
    req = urllib2.Request(url='https://survey.inresearch.com.sg/index.php/admin/remotecontrol',\
                          data='{\"method\":\"list_participants\",\
                                  "params\":[\"'+skey+'\",\"'+sid+'\",\"0\",\"10000\"],\"id\":1}')
    req.add_header('content-type', 'application/json')
    req.add_header('connection', 'Keep-Alive')
    try:
        f = urllib2.urlopen(req)
        myretun = f.read()
        #print myretun
        j=json.loads(myretun)
        return j['result']
    except :
        e = sys.exc_info()[0]
        print ( "
Error: %s
" % e )

###############################################################################
###############################################################################

# select working directory and update the label for it (below)
def select_directory():
    directory = tkFileDialog.askdirectory(title='Select folder datafile is located in...')
    try:
        os.chdir(directory)
        return(directory)
    except:
        print('Directory was not selected')
        pass

def update_directory(stringVar):
    directory = select_directory()
    try:
        stringVar.set('Selected Directory: ' + directory)
    except:
        print('Could not update directory')
        pass

# select the csv file and update the label for it(below)
def select_datafile():
    datafile = os.path.basename(tkFileDialog.askopenfilename(title='Select CSV',initialdir=os.getcwd()))
    if datafile == '':
       datafile = "No file selected"
    return datafile

def update_datafile(dataVar, stringVar):
    datafile = select_datafile()
    try:
        stringVar.set('Selected CSV: ' + datafile)
        dataVar.set(datafile)
    except:
        print('Could not update to selected CSV')
        pass

#to refresh survey list upon log in (see below)
def refresh_survey_list(menuButton, menuVar, skey, user):
    menuVar.set('')
    menuButton['menu'].delete(0, 'end')
    surveyDic = get_survey_dic(skey, user)
    new_choices = list(surveyDic)
    for choice in new_choices:
        menuButton['menu'].add_command(label=choice, command=tk._setit(menuVar, surveyDic[choice]))

# 'log in'
def update_session_key(user, pw, keyString, resultVar, menuButton, menuVar):
    key = get_session_key(user, pw)
    if type(key) == dict:
        resultVar.set(key['status'])
    else:
        try:
            keyString.set(key)
            resultVar.set('Log in success!')
            refresh_survey_list(menuButton, menuVar, key, user)
            menuVar.set('No Survey Selected')
            print(key)
        except:
            resultVar.set('Log in failure')
            print('Could not set key to variable')
            pass

def getDic(inFile, statusVar):
    dic ={}
    if inFile.endswith('.csv'):
        with open(inFile, 'r') as readcsv:
            reader = csv.reader(readcsv)
            for row in reader:
                try:
                    dic[row[0]] = row[1]
                except IndexError:
                    dic[row[0]] = ''
        return dic
    else:
        return None

def change_emails_tid(master, skey, sid, statusVar, inFile):
    dic = getDic(inFile, statusVar)
    if dic == None:
        statusVar.set('You did not select a csv')
    else:
        timerCounter = 1.00
        tokenList = list_participants(skey,sid)
        for token in tokenList:
            try:
                tokenID = token['tid']
            except:
                continue
            if tokenID in dic:
                set_participant_email(skey, sid, token['tid'], dic[tokenID])
                print('Token ID: ' + token['tid'])
                print(str(tokenID) + '\'s email changed to: ' + dic[tokenID])
            currentTimer = int(timerCounter/float(len(tokenList))*100)
            if currentTimer%5== 0:
                statusVar.set(str(currentTimer)+'%')
                master.update_idletasks()
            timerCounter += 1.00

def change_emails_email(master, skey, sid, statusVar, inFile):
    dic = getDic(inFile, statusVar)
    if dic == None:
        statusVar.set('You did not select a csv')
    else:
        timerCounter = 1.00
        tokenList = list_participants(skey,sid)
        for token in tokenList:
            try:
                tokenEmail = token['participant_info']['email']
            except:
                continue
            if tokenEmail in dic:
                set_participant_email(skey, sid, token['tid'], dic[tokenEmail])
                print('Token ID: ' + token['tid'])
                print(str(tokenEmail) + ' changed to: ' + dic[tokenEmail])
            currentTimer = int(timerCounter/float(len(tokenList))*100)
            if currentTimer%5== 0:
                statusVar.set(str(currentTimer)+'%')
                master.update_idletasks()
            timerCounter += 1.00

def change_emails_token(master, skey, sid, statusVar, inFile):
    dic = getDic(inFile, statusVar)
    if dic == None:
        statusVar.set('You did not select a csv')
    else:
        timerCounter = 1.00
        tokenList = list_participants(skey,sid)
        for token in tokenList:
            try:
                tokenToken = token['token']
            except:
                continue
            if tokenToken in dic:
                set_participant_email(skey, sid, token['tid'], dic[tokenToken])
                print('Token ID: ' + token['tid'])
                print(str(tokenToken) + '\'s email changed to: ' + dic[tokenToken])
            currentTimer = int(timerCounter/float(len(tokenList))*100)
            if currentTimer%5== 0:
                statusVar.set(str(currentTimer)+'%')
                master.update_idletasks()
            timerCounter += 1.00

def get_survey_dic(skey, user):
    try:
        surveyList = list_surveys(skey, user)
        surveyDic = {}
        for survey in surveyList:
            surveyDic[survey['surveyls_title']] = survey['sid']
        return(surveyDic)
    except:
        print('could not get survey list from LS')
        return['No survey selected']
###############################################################################
###############################################################################

'''
changeEmails(dic)
print(release_session_key(mykey))'''

class MainApplication(tk.Frame):
    def __init__(self, master, *args, **kwargs):
        tk.Frame.__init__(self, master, *args, **kwargs)
        self.master = master
        self.init_window()

    def init_window(self):
        self.master.title('Email changer')
        self.variables = Variables(self.master)
        self.buttons = Buttons(self.master, self.variables)
        self.body = Body(self.master, self.buttons, self.variables)

class Body(tk.Frame):
    def __init__(self, master, buttons, variables):

        ##### LABELS #####

        userLabel = tk.Label(master, text='Username: ')
        userLabel.grid(row=0, column=0)
        passLabel = tk.Label(master, text='Password: ')
        passLabel.grid(row=1, column=0)
        logInStatusLabel = tk.Label(master, textvariable=variables.logInStatusVar)
        logInStatusLabel.grid(row=1, column=2)
        dirLabel = tk.Label(master, textvariable = variables.dirVar)
        dirLabel.grid(row=2, column=1)
        csvLabel = tk.Label(master, textvariable = variables.csvTextVar)
        csvLabel.grid(row=3, column=1)
        statusLabel = tk.Label(master, textvariable= variables.statusVar)
        statusLabel.grid(row=5, column=1)

class Buttons(tk.Frame):
    def __init__(self, master, variables):
        userEntry = tk.Entry(master, textvariable=variables.userVar)
        userEntry.grid(row=0, column=1)
        passEntry = tk.Entry(master, textvariable=variables.passVar, show='*')
        passEntry.grid(row=1, column=1)

        changeDirButton = tk.Button(master, text='Select Directory', command=
                                    lambda: update_directory(variables.dirVar))
        changeDirButton.grid(row=2, column=0, sticky=tk.W+tk.E)
        selectCSVButton = tk.Button(master, text='Select CSV', command=
                                    lambda: update_datafile(variables.csvVar,variables.csvTextVar))
        selectCSVButton.grid(row=3, column=0, sticky=tk.W+tk.E)
        selectSurveyMenu = tk.OptionMenu(master, variables.surveyListVar, *['test','test'])
        selectSurveyMenu.grid(row=4,column=0)
        getKeyButton = tk.Button(master, text='Log In', command=
                                 lambda: update_session_key(userEntry.get(),passEntry.get(),variables.keyVar, variables.logInStatusVar, selectSurveyMenu,variables.surveyListVar))
        getKeyButton.grid(row=0,column=2,sticky=tk.W+tk.E)

        #################### just testing ########################
        changeEmailsIDButton = tk.Button(master, text='Change Emails (token ID)', command=
                                       lambda: change_emails_tid(master,variables.keyVar.get(),variables.surveyListVar.get(),variables.statusVar, variables.csvVar.get()))
        changeEmailsIDButton.grid(row=3,column=2, sticky=tk.W+tk.E)
        changeEmailsTokenButton = tk.Button(master, text='Change Emails (token)', command=
                                       lambda: change_emails_token(master,variables.keyVar.get(),variables.surveyListVar.get(),variables.statusVar, variables.csvVar.get()))
        changeEmailsTokenButton.grid(row=4,column=2, sticky=tk.W+tk.E)
        changeEmailsEmailButton = tk.Button(master, text='Change Emails (email)', command=
                                       lambda: change_emails_email(master,variables.keyVar.get(),variables.surveyListVar.get(),variables.statusVar, variables.csvVar.get()))
        changeEmailsEmailButton.grid(row=5,column=2, sticky=tk.W+tk.E)

class Variables(tk.Frame):
    def __init__(self, master):
        self.userVar = tk.StringVar()
        self.passVar = tk.StringVar()
        self.logInStatusVar = tk.StringVar()
        self.keyVar = tk.StringVar()
        self.dirVar = tk.StringVar()
        self.dirVar.set(os.getcwd())
        self.csvVar = tk.StringVar()
        self.csvTextVar = tk.StringVar()
        self.csvTextVar.set('No CSV selected')
        self.surveyListVar = tk.Variable()
        self.surveyListVar.set('Select Survey')
        self.statusVar = tk.StringVar()

if __name__ == "__main__":
    root = tk.Tk()
    MainApplication(root)
    root.mainloop()


from django.core.management.base import BaseCommand, CommandError
from django.core.exceptions import *
from django.db import IntegrityError
from django.db import connection
from django.core.cache import cache
from django.db.models import Count
from marimobackend.models import *
from marimobackend.serializers import *
from optparse import make_option
from bs4 import BeautifulSoup
from multiprocessing import Pool
from cfscrape import cfscrape
import requests
import string
import re
import datetime
import mechanicalsoup

BASE_URL = "http://kissanime.com"
ANIME_LIST_URL = "http://kissanime.com/AnimeList"
UPDATE_URL = "http://kissanime.com/AnimeList/LatestUpdate"
LOGIN_URL = "http://kissanime.com/Login"

class Command(BaseCommand):
    help = 'Scrapes all of KissAnime.'
    option_list = BaseCommand.option_list + (
        make_option('--update',
                    action='store_true',
                    dest='update',
                    default=False,
                    help='Scrapes the latest updates from KissAnime.'),
        make_option('--cache',
                    action='store_true',
                    dest='cache',
                    default=False,
                    help='Cache data after scraping.')
        )

    def handle(self, *args, **options):
        scraper = Scraper(should_update=options['update'],
                          should_cache=options['cache'])
        scraper.scrape()

class Scraper:
    def __init__(self, should_update, should_cache):
        self.should_update = should_update
        self.should_cache = should_cache
        self.session = None
        self.urls = None

    def scrape(self):
        self.login()
        self.update_potential_categories()
        self.scrape_anime_list()
        for url in self.urls:
            self.scrape_anime(url)
        if self.should_cache:
            self.cache_anime()

    def login(self):
        """
        Login in order to bypass restrictions.
        """
        print('Logging in...')
        try:
            cloudflare_scraper = cfscrape.create_scraper()
            cloudflare_scraper.get(LOGIN_URL)
            browser = mechanicalsoup.Browser(session=cloudflare_scraper)
        except RuntimeError:
            browser = mechanicalsoup.Browser()

        login_page = browser.get(LOGIN_URL)
        login_form = login_page.soup.select("#formLogin")[0]
        login_form.select("input#username")[0]['value'] = 'hey123123'
        login_form.select("input#password")[0]['value'] = '123123123'
        browser.submit(login_form, login_page.url)
        self.session = browser.session

    def update_potential_categories(self):
        """
        Store the categories in advance to prevent race conditions.
        """
        page = self.session.get(ANIME_LIST_URL)
        soup = BeautifulSoup(page.text)
        categories = soup.select('a[href^=/Genre/]')
        for category in categories:
            text = category.text.lstrip()
            try:
                cat = Category.objects.get(name=text)
            except Category.DoesNotExist:
                cat = Category(name=text)
                cat.save()

    def cache_anime(self):
        """
        Cache the newly scraped anime.
        """
        updated_anime = Anime.objects.filter().annotate(num_episodes=Count('episode')).filter(num_episodes__gt=0)
        serialized_anime = AnimeSerializer(updated_anime, many=True)
        data = serialized_anime.data
        cache.set('anime_list', data, None)

    def scrape_anime_list(self):
        """
        Recursively scrapes urls and names of every anime series in the anime list.
        """
        def get_last_page():
            """
            Finds the page number of the last page in the anime list so we know
            when the list is over.
            """
            page = self.session.get(ANIME_LIST_URL)
            soup = BeautifulSoup(page.text)
            last_page_num = soup.select('a[href^=/AnimeList?page=]')[-1]['page']
            return int(last_page_num)

        def scrape_page(page_num, anime_list=[]):
            """
            Scrapes each page in the anime list.
            """
            page = self.session.get(ANIME_LIST_URL + "?page=" + str(page_num))
            soup = BeautifulSoup(page.text)
            for anime in soup.select('a[href^=/Anime/]'):
                anime_list.append(anime)
            if page_num == last_page:
                return anime_list
            else:
                return scrape_page(page_num + 1, anime_list)

        def filter_anime(anime_data):
            """
            Filters out unwanted scraped urls.
            """
            anime_list = []
            for anime in anime_data:
                text = anime.text.lstrip()
                if not re.match("Episode", text) \
                and not re.match("^OVA", text) \
                and not re.match("^OAD", text) \
                and not re.match("_Preview", text) \
                and not re.match("^_Ending Preview", text) \
                and not re.match("13 - Shield and", text) \
                and not re.match('_CM', text):
                    anime_list.append(BASE_URL + anime['href'])
            return anime_list

        def scrape_updates():
            """
            Scrapes a list of only the latest updates.
            """
            page = self.session.get(UPDATE_URL)
            soup = BeautifulSoup(page.text)
            anime_list = []
            for anime in soup.select('a[href^=/Anime/]'):
                anime_list.append(anime)
            return anime_list

        if self.should_update:
            raw_data = scrape_updates()
            self.urls = filter_anime(raw_data)
        else:
            last_page = get_last_page()
            raw_data = scrape_page(0)
            self.urls = filter_anime(raw_data)

    def scrape_anime(self, url):
        """
        Scrapes all information and episode urls for a given anime series.
        i.e: http://kissanime.com/Anime/Psycho-Pass-2
        >>> x = scrape_anime('http://kissanime.com/Anime/Psycho-Pass-2')
        >>> x.episodes[0].date
        '12/18/2014'
        """
        connection.close()
        page = self.session.get(url)
        soup = BeautifulSoup(page.text)

        def get_anime_info():
            info = {}
            title = soup.find('a', class_='bigChar').text
            print("Scraping Anime: " + title)
            image = soup.select('div.barContent > div > img')[0]['src']
            for x in soup.select('div.barContent > div > p > span.info'):
                value = x.next_siblings.__next__().strip()
                if x.text.strip() == 'Date aired:':
                    info['date'] = value
                elif x.text.strip() == 'Views:':
                    info['views'] = int(value.replace(',', ''))
                elif x.text.strip() == 'Status:':
                    info['status'] = value

            summary = ''
            try:
                for s in soup.select('div.barContent > div > p ')[-1].contents[3].contents:
                    try:
                        summary += s + ' '
                    except:
                        continue
            except:
                summary += soup.select('div.barContent > div > p ')[-1].next_sibling.strip()

            info['title'] = title
            info['image'] = image
            info['summary'] = summary
            return info

        def get_anime():
            info = get_anime_info()
            try:
                anime = Anime.objects.get(url=url)
                anime.title = info['title']
                anime.cover_image = info['image']
                anime.date_aired = info.get('date', None)
                anime.status = info['status']
                anime.views = info['views']
                anime.origin = "KissAnime"
                anime.save()

            except Anime.DoesNotExist:
                anime = Anime(title=info['title'],
                          cover_image=info['image'],
                          date_aired=info.get('date', None),
                          status=info['status'],
                          views=info['views'],
                          origin="KissAnime",
                          summary=info['summary'],
                          url=url)
                anime.save()
            except IntegrityError:
                    return
            return anime

        def get_categories():
            genres = soup.select('div.barContent > div > p > a[href^=/Genre]')
            for category in genres:
                cat = Category.objects.get(name=category.text)
                anime.categories.add(cat)
                cat.animes.add(anime)

        def get_alternate_names():
            other_names = soup.select('div.barContent > div > p > a[href^=/Anime]')
            for alt in other_names:
                try:
                    AlternateName.objects.get(name=alt.text, anime=anime)
                except AlternateName.DoesNotExist:
                    name = AlternateName(name=alt.text, anime=anime)
                    anime.alternatename_set.add(name)

        def get_episodes():
            episode_base = url.replace(BASE_URL, '')
            episode_base = episode_base.replace(' ', '-')
            episode_data = soup.select('a[href^=' + episode_base + '/Episode]')
            if episode_data:
                episode_data = episode_data[:-1] #Get rid of unwanted fake episode
            # Note: If the `episodes` are actually movies or OVAs, this will not detect them, so we have to try movies as well.
            if not episode_data:
                episode_data = soup.select('a[href^=' + episode_base + '/Movie]')
            if not episode_data:
                episode_data = soup.select('a[href^=' + episode_base + '/OVA]')
            for raw_episode in episode_data:
                episode_title = raw_episode.text.lstrip()
                date_data = raw_episode.parent.next_siblings
                for s in date_data:
                    if s != '\n':
                        date = s.text.strip()
                        try:
                            date = datetime.datetime.strptime(date, '%m/%d/%Y').date()
                        except:
                            date = datetime.datetime.now().strftime('%m/%d/%Y')
                try:
                    episode = anime.episode_set.get(title=episode_title)
                except Episode.DoesNotExist:
                    print('Scraping new episode:' + episode_title)
                    episode = Episode(title=episode_title, date=date, anime=anime)
                    episode.save()
                    anime.episode_set.add(episode)
                except IntegrityError:
                    pass
                if episode.video_set.count() <= 0:
                    print("Scraping videos...")
                    get_videos(BASE_URL + raw_episode['href'], episode)
            refresh_for_video_updates(episode_data)
            anime.save()

        def get_videos(episode_url, episode):
            """
            Scrapes the different quality video URLs for a given episode.
            i.e: "http://kissanime.com/Anime/Fate-stay-night-2014/Episode-007?id=82557"
            """
            page = self.session.get(episode_url)
            soup = BeautifulSoup(page.text)
            video_data =  soup.select('#divDownload')
            if video_data:
                for video in video_data[0].find_all('a'):
                    try:
                        Video.objects.get(quality=video.text, episode=episode)
                    except Video.DoesNotExist:
                        vid = Video(quality=video.text, link=video['href'], episode=episode)
                        vid.save()
                        episode.video_set.add(vid)
                    except IntegrityError:
                        connection.close()

        def refresh_for_video_updates(episode_data):
            """
            Check the latest episode again to make sure no additional quality videos have been added.
            """
            try:
                episode_title = episode_data[0].text.lstrip()
                episode = anime.episode_set.get(title=episode_title)
                if episode.video_set.count() <= 3:
                    print('Checking for video updates...')
                    get_videos(BASE_URL+ episode_data[0]['href'], episode)
            except:
                pass

        anime = get_anime()
        get_categories()
        get_alternate_names()
        get_episodes()

        if self.should_cache:
            if cache.get(str(anime.pk)):
                cache.delete(anime.pk)


# -*- coding: utf-8 -*-
# See LICENSE file for full copyright and licensing details.
import base64
import csv
import json
import logging
import time

from datetime import datetime, timedelta
from io import StringIO, BytesIO

from odoo import api, models, fields, _
from odoo.exceptions import UserError
from odoo.tools.misc import split_every

_logger = logging.getLogger("WooCommerce")

class WooProcessImportExport(models.TransientModel):
    _name = 'woo.process.import.export'
    _description = "WooCommerce Import/Export Process"

    woo_instance_id = fields.Many2one("woo.instance.ept", "Instance", domain=[("active", "=", True)])
    woo_operation = fields.Selection([
        ('import_product', 'Import Products'),
        ('import_customer', 'Import Customers'),
        ('import_unshipped_orders', 'Import Unshipped Orders'),
        ('import_completed_orders', 'Import Completed Orders'),
        ('is_update_order_status', 'Update Order Shipping Status'),
        ('import_product_tags', 'Import Product Tags'),
        ('import_attribute', 'Import Attributes'),
        ('import_category', 'Import Categories'),
        ('import_coupon', 'Import Coupons'),
        ('import_stock', 'Import Stock'),
        ('export_stock', 'Export Stock'),
        ("update_tags", "Update Tags"),
        ("export_tags", "Export Tags"),
        ('update_category', 'Update Categories'),
        ('export_category', 'Export Categories'),
        ('update_coupon', 'Update Coupons'),
        ('export_coupon', 'Export Coupons'),
        ('import_product_from_csv', 'Import Product From CSV')
    ], string="Operation")
    woo_skip_existing_product = fields.Boolean(string="Do not update existing products",
                                               help="Check if you want to skip existing products in"
                                                    " odoo", default=False)
    orders_before_date = fields.Datetime("To")
    orders_after_date = fields.Datetime("From")
    woo_is_set_price = fields.Boolean(string="Woo Set Price ?")
    woo_is_set_stock = fields.Boolean(string="Woo Set Stock ?")
    woo_publish = fields.Selection([('publish', 'Publish'), ('unpublish', 'Unpublish')],
                                   string="Publish In Website ?",
                                   help="If select publish then Publish the product in website and"
                                        " If the select unpublish then Unpublish the product "
                                        "from website")
    woo_is_set_image = fields.Boolean(string="Woo Set Image ?", default=False)
    woo_basic_detail = fields.Boolean(string="Basic Detail", default=True)
    export_stock_from = fields.Datetime(help="It is used for exporting stock from Odoo to Woo.")
    import_products_method = fields.Selection([("import_all", "Import all"),
                                               ("new_and_updated", "New and Updated Only")],
                                              "Products to Import",
                                              default="new_and_updated")
    choose_file = fields.Binary(help="Select CSV file to upload.")
    file_name = fields.Char(help="Name of CSV file.")
    csv_data = fields.Binary('CSV File', readonly=True, attachment=False)
    cron_process_notification = fields.Text(string="Note: ", store=False,
                                            help="Used to display that cron will be run after some time")
    is_hide_execute_button = fields.Boolean(default=False, store=False, help="Used to hide the execute button from "
                                                                             "opration wizard while seleted opration cron is running in backend")

    @api.constrains('orders_after_date', 'orders_before_date')
    def _check_order_after_before_date(self):
        """
        Constraint for from and to date of import order process.
        @author: Maulik Barad on Date 08-Jan-2019.
        """
        if self.woo_operation in ['import_unshipped_orders',
                                  'import_completed_orders'] and self.orders_before_date <= self.orders_after_date:
            raise UserError(_("From date should be less than To date.\nPlease enter proper date range for import "
                              "order process."))

    @api.onchange('woo_operation')
    def _onchange_woo_operation(self):
        """ Onchange method of Instance as need to set the From date for import order process.
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 3 September 2020 .
            Task_id: 165893
        """
        self.cron_process_notification = False
        self.is_hide_execute_button = False
        from_date = fields.Datetime.now() - timedelta(days=1)
        if self.woo_instance_id:
            if self.woo_instance_id.last_order_import_date and self.woo_operation == 'import_unshipped_orders':
                self.orders_after_date = self.woo_instance_id.last_order_import_date
            elif self.woo_instance_id.last_completed_order_import_date and self.woo_operation == 'import_completed_orders':
                self.orders_after_date = self.woo_instance_id.last_completed_order_import_date
            else:
                self.orders_after_date = from_date
            if self.woo_instance_id.last_inventory_update_time:
                self.export_stock_from = self.woo_instance_id.last_inventory_update_time
            else:
                self.export_stock_from = fields.Datetime.now() - timedelta(days=30)
        else:
            self.orders_after_date = from_date
        if self.woo_operation == 'import_unshipped_orders':
            self.woo_check_running_schedulers('ir_cron_woo_import_order_instance_')
        if self.woo_operation == 'is_update_order_status':
            self.woo_check_running_schedulers('ir_cron_woo_update_order_status_instance_')
        if self.woo_operation == 'export_stock':
            self.woo_check_running_schedulers('ir_cron_update_woo_stock_instance_')
        self.orders_before_date = fields.Datetime.now()

    def execute(self):
        """
        This method is used to perform the selected operation.
        """
        queues = False
        if self.woo_operation == "import_customer":
            queues = self.woo_import_customers()
            action = self.env.ref("woo_commerce_ept.woo_customer_data_queue_ept_action").sudo().read()[0]
            form_view = [(self.env.ref('woo_commerce_ept.woo_customer_data_data_queue_ept_form_view').id, 'form')]
        elif self.woo_operation == "import_product":
            queues = self.get_products_from_woo()
            action = self.env.ref("woo_commerce_ept.action_woo_product_data_queue_ept").sudo().read()[0]
            form_view = [(self.env.ref('woo_commerce_ept.woo_product_data_queue_form_view_ept').id, 'form')]
        elif self.woo_operation == "import_product_tags":
            self.sync_product_tags()
        elif self.woo_operation == "import_attribute":
            self.sync_woo_attributes()
        elif self.woo_operation == "import_category":
            self.sync_woo_product_category()
        elif self.woo_operation == "import_unshipped_orders":
            self.import_sale_orders()
        elif self.woo_operation == "import_completed_orders":
            queues = self.import_sale_orders(order_type='completed')
            action = self.env.ref("woo_commerce_ept.action_woo_order_data_queue_ept").sudo().read()[0]
            form_view = [(self.env.ref('woo_commerce_ept.view_woo_order_data_queue_ept_form').id, 'form')]
        elif self.woo_operation == "is_update_order_status":
            self.update_order_status()
        elif self.woo_operation == 'import_stock':
            self.import_stock()
        elif self.woo_operation == "export_stock":
            self.update_stock_in_woo()
        elif self.woo_operation == "update_tags":
            self.update_tags_in_woo()
        elif self.woo_operation == "export_tags":
            self.export_tags_in_woo()
        elif self.woo_operation == "update_category":
            self.update_product_categ()
        elif self.woo_operation == "export_category":
            self.export_product_categ()
        elif self.woo_operation == "import_coupon":
            queues = self.import_woo_coupon()
            action = self.env.ref("woo_commerce_ept.action_woo_coupon_data_queue_ept").sudo().read()[0]
            form_view = [(self.env.ref('woo_commerce_ept.view_woo_coupon_data_queue_ept_form').id, 'form')]
        elif self.woo_operation == "export_coupon":
            self.export_woo_coupons()
        elif self.woo_operation == "update_coupon":
            self.update_woo_coupons()
        elif self.woo_operation == "import_product_from_csv":
            self.import_products_from_csv()

        if queues:
            if len(queues) > 1:
                action["domain"] = [("id", "in", queues)]
            else:
                action['views'] = form_view
                action['res_id'] = queues[0]
            return action

        return {
            'type': 'ir.actions.client',
            'tag': 'reload',
        }

    def sync_woo_product_category(self, woo_instance=False):
        """
        This method is used for create a woo product category based on category response.
        :param woo_instance: It contain the browsable object of the current instance.
        :return: It will return True if the process successfully completed.
        @author: Dipak Gogiya @Emipro Technologies Pvt. Ltd
        """
        woo_category_obj = self.env['woo.product.categ.ept']
        woo_common_log_obj = self.env["common.log.book.ept"]
        if self:
            woo_instance = self.woo_instance_id
        woo_common_log_id = woo_common_log_obj.woo_create_log_book('import', woo_instance)

        woo_category_obj.sync_woo_product_category(woo_instance, woo_common_log_id,
                                                   sync_images_with_product=woo_instance.sync_images_with_product)

        if not woo_common_log_id.log_lines:
            woo_common_log_id.unlink()
        self._cr.commit()

        return True

    def sync_woo_attributes(self, woo_instance=False):
        """
        This method is used for create a product attribute with its values based on received product attributes
        response.
        :param woo_instance: It contain the browsable object of the current instance
        :return: It will return true if the process successful complete
        @author: Dipak Gogiya @Emipro Technologies Pvt. Ltd
        """
        woo_common_log_obj = self.env["common.log.book.ept"]
        woo_template_obj = self.env['woo.product.template.ept']

        if self:
            woo_instance = self.woo_instance_id

        woo_common_log_id = woo_common_log_obj.woo_create_log_book('import', woo_instance)
        woo_template_obj.sync_woo_attribute(woo_instance, woo_common_log_id)

        if not woo_common_log_id.log_lines:
            woo_common_log_id.unlink()

        return True

    def sync_product_tags(self, woo_instance=False):
        """
        This method is used for create a product tags based on received response of product tags.
        :param woo_instance: It contain the browsable object of the current instance
        :return: It will return True if the process successfully completed
        @author: Dipak Gogiya @Emipro Technologies Pvt. Ltd
        """
        woo_common_log_obj = self.env["common.log.book.ept"]
        product_tags_obj = self.env['woo.tags.ept']

        if self:
            woo_instance = self.woo_instance_id

        woo_common_log_id = woo_common_log_obj.woo_create_log_book('import', woo_instance)

        product_tags_obj.woo_sync_product_tags(woo_instance, woo_common_log_id)

        if not woo_common_log_id.log_lines:
            woo_common_log_id.unlink()

        return True

    def woo_import_customers(self):
        """ This method used for get customers and generate queue for import process.
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 28 August 2020.
            Task_id: 165956
        """
        start = time.time()
        res_partner_obj = self.env['res.partner']
        common_log_obj = self.env["common.log.book.ept"]
        common_log_id = common_log_obj.woo_create_log_book('import', self.woo_instance_id)

        customer_queues = res_partner_obj.with_context(import_export_record_id=self.id).woo_get_customers(
            common_log_id, self.woo_instance_id)

        if not common_log_id.log_lines:
            common_log_id.unlink()

        end = time.time()
        _logger.info("Created customer queues time -- %s -- seconds.", str(end - start))

        return customer_queues

    def prepare_data_and_import_stock(self):
        """
        This method is used for prepare data for import stock.
        @author: Pragnadeep Pitroda @Emipro Technologies Pvt. Ltd 16-Nov-2019
        :Task id: 156886
        Migration done by Haresh Mori @ Emipro on date 22 September 2020 .
        """
        common_log_obj = self.env["common.log.book.ept"]
        woo_product = self.env['woo.product.product.ept']
        common_log_line_obj = self.env["common.log.lines.ept"]
        model = "woo.product.product.ept"
        model_id = common_log_line_obj.get_model_id(model)
        instance = self.woo_instance_id
        products_stock = []
        duplicate_woo_product = []
        log_lines = []

        woo_products = woo_product.search([('exported_in_woo', '=', True), ('woo_instance_id', '=', instance.id)])
        sku = woo_products.mapped('default_code')
        product_fields = 'id,name,sku,manage_stock,stock_quantity'

        for sku_chunk in split_every(100, sku):
            res_products, log_lines = self.request_for_import_stock(sku_chunk, instance, product_fields, model_id,
                                                                    common_log_line_obj, log_lines)
            for res_product in res_products:
                products_stock, duplicate_woo_product, log_lines = self.prepare_data_for_inventory_adjustment(
                    woo_products, res_product, duplicate_woo_product, products_stock, common_log_line_obj, model_id,
                    log_lines)

        if log_lines:
            common_log_obj.woo_create_log_book('import', instance, log_lines)

        return products_stock

    def request_for_import_stock(self, sku_chunk, instance, product_fields, model_id, common_log_line_obj, log_lines):
        """ This method is used call request for the import stock.
            @param sku_chunk: Bunch of woo template sku
            @param instance:
            @param product_fields: Domain for which value need in response.
            @param model_id:
            @param common_log_line_obj:
            @param log_lines:
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 6 November 2020 .
            Task_id: 168147 - Code refactoring : 5th - 6th November
        """
        product_response = []
        try:
            wcapi = instance.woo_connect()
            str_sku = ",".join(sku_chunk)
            res = wcapi.get("products", params={'sku': str_sku, '_fields': product_fields, 'per_page': 100})
            if res.status_code not in [200, 201]:
                log_line_id = common_log_line_obj.create({'model_id': model_id,
                                                          'message': 'Import Stock for products has not proper '
                                                                     'response.\n Response %s' % res.content})
                log_lines.append(log_line_id.id)

            product_response = res.json()

        except Exception as error:
            log_line_id = common_log_line_obj.create({'model_id': model_id,
                                                      'message': 'Import Stock for products not perform.\n Error %s' % (
                                                          error)})
            log_lines.append(log_line_id.id)

        return product_response, log_lines

    def prepare_data_for_inventory_adjustment(self, woo_products, res_product, duplicate_woo_product, products_stock,
                                              common_log_line_obj, model_id, log_lines):
        """ This method is used to prepare a data for inventory adjustmet.
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 6 November 2020 .
            Task_id: 168147 - Code refactoring : 5th - 6th November
        """
        stock_data = {}
        product = woo_products.filtered(lambda x: x.default_code == res_product.get('sku'))
        if product:
            if res_product.get('manage_stock') and res_product.get('stock_quantity') and product.product_id.type \
                =='product':
                product_qty = res_product.get('stock_quantity')
                stock_data.update({'product_qty': product_qty})
                stock_data.update({'product_id': product.product_id})
                if product.product_id.id not in duplicate_woo_product:
                    _logger.info("Adding dict in Woo product list for inventory adjustment: %s for Woo product "
                                 "variant ID: %s", stock_data, product.variant_id)
                    products_stock.append(stock_data)
                    duplicate_woo_product.append(product.product_id.id)
                else:
                    _logger.info("== Duplicate product available in Woocmmerce store with SKU: %s ",
                                 product.default_code)
        else:
            log_line_id = common_log_line_obj.create({
                'model_id': model_id,
                'message': 'Import Stock for product %s does not exist in odoo' % (res_product.get('sku')),
            })
            log_lines.append(log_line_id.id)

        return products_stock, duplicate_woo_product, log_lines

    def import_stock(self):
        """
        This method is used for import stock. In which call methods for prepare stock data.
        @author: Pragnadeep Pitroda @Emipro Technologies Pvt. Ltd on date 08-11-2019.
        :Task id: 156886
        Migration done by Haresh Mori @ Emipro on date 22 September 2020 .
        """
        instance = self.woo_instance_id

        products_stock = self.prepare_data_and_import_stock()

        if products_stock:
            _logger.info("Going for the create inventory adjustment....")
            self.env['stock.inventory'].create_stock_inventory_ept(products_stock,
                                                                   instance.woo_warehouse_id.lot_stock_id,
                                                                   auto_validate=False)
            _logger.info("Created inventory adjustment and inventory adjustment line.")
        return True

    def update_stock_in_woo(self):
        """
        This method call child method for update stock from Odoo to Woocommerce.
        @author: Pragnadeep Pitroda @Emipro Technologies Pvt. Ltd on date 16-11-2019.
        :Task id: 156886
        Migration done by Haresh Mori @ Emipro on date 11 September 2020 .
        """
        instance = self.woo_instance_id
        self.env['woo.product.template.ept'].update_stock(instance, self.export_stock_from)

        return True

    def get_products_from_woo(self):
        """
        This method used to get products with its variants from woo commerce store.
        @author: Dipak Gogiya @Emipro Technologies Pvt. Ltd.
        Migration done by Haresh Mori @ Emipro on date 13 August 2020.
        Task_Id: 165892
        """
        start = time.time()
        woo_products_template_obj = self.env['woo.product.template.ept']
        woo_common_log_obj = self.env["common.log.book.ept"]
        woo_instance_id = self.woo_instance_id
        import_all = True if self.import_products_method == "import_all" else False
        woo_common_log_id = woo_common_log_obj.woo_create_log_book('import', self.woo_instance_id)
        self.sync_woo_product_category(woo_instance_id)
        self.sync_product_tags(woo_instance_id)
        self.sync_woo_attributes(woo_instance_id)
        product_queues = woo_products_template_obj.with_context(
            import_export_record=self.id).get_products_from_woo_v1_v2_v3(woo_instance_id,
                                                                         woo_common_log_id,
                                                                         import_all=import_all)
        if not woo_common_log_id.log_lines:
            woo_common_log_id.unlink()

        end = time.time()
        _logger.info("Created product queues time -- %s -- seconds.", str(end - start))

        return product_queues

    def woo_create_customer_queue(self, customers, created_by="import"):
        """ This method used to create a customer queue base on the customer response.
            :param customers: Customer response as received from Woocommerce store.
            @return: queues: Record of customer queues
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 28 August 2020.
            Task_id: 165956
        """
        woo_sync_customer_obj = queues = self.env['woo.customer.data.queue.ept']
        woo_sync_customer_data = self.env['woo.customer.data.queue.line.ept']

        for customer_queue in split_every(101, customers):
            queue = woo_sync_customer_obj.create({"woo_instance_id": self.woo_instance_id.id, 'created_by': created_by})
            _logger.info("Created customer queue: %s", queue.display_name)
            sync_vals = {'woo_instance_id': self.woo_instance_id.id, 'queue_id': queue.id}

            for customer in customer_queue:
                sync_vals.update({
                    'last_process_date': datetime.now(),
                    'woo_synced_data': json.dumps(customer),
                    'woo_synced_data_id': customer.get('id'),
                    'name': customer.get('first_name') + " " + customer.get('last_name') if customer.get(
                        'first_name') else customer.get('username')
                })
                woo_sync_customer_data.create(sync_vals)
            queues += queue
        return queues

    def woo_import_products(self, woo_products, created_by="import"):
        """
        This method used to create a new product queue based on received product response from woocommerce.
        @param : self :- It contain the object of current class
        @param : woo_products - It contain the products of woo commerce and its type is list
        @author: Dipak Gogiya @Emipro Technologies Pvt. Ltd.
        Migration done by Haresh Mori @ Emipro on date 13 August 2020.
        Task_Id: 165892
        """
        woo_product_synced_queue_line_obj = self.env['woo.product.data.queue.line.ept']
        is_sync_image_with_product = 'done'
        queue_obj = self.create_product_queue(created_by)
        _logger.info("Product Data Queue %s created. Adding data in it.....", queue_obj.name)
        queue_obj_list = [queue_obj]
        sync_queue_vals_line = self.prepare_product_queue_line_vals(queue_obj)
        if self.woo_instance_id.sync_images_with_product:
            is_sync_image_with_product = 'pending'
        for woo_product in woo_products:
            sync_queue_vals_line.update(
                {
                    'woo_synced_data': json.dumps(woo_product),
                    'woo_update_product_date': woo_product.get('date_modified'),
                    'woo_synced_data_id': woo_product.get('id'),
                    'name': woo_product.get('name'),
                    'image_import_state': is_sync_image_with_product
                })

            woo_product_synced_queue_line_obj.create(sync_queue_vals_line)
            if len(queue_obj.queue_line_ids) == 101:
                queue_obj = self.create_product_queue(created_by)
                _logger.info("Product Data Queue %s created. Adding data in it.....", queue_obj.name)
                queue_obj_list.append(queue_obj)
                sync_queue_vals_line = self.prepare_product_queue_line_vals(queue_obj)
                continue
        for queue_obj in queue_obj_list:
            if not queue_obj.queue_line_ids:
                queue_obj.unlink()
        return queue_obj

    def create_product_queue(self, created_by):
        """This method used to create a product data queue.
            @return: product_queue: Record of product queue.
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 13 August 2020.
            Task_id:165892
        """
        woo_product_synced_queue_obj = self.env['woo.product.data.queue.ept']
        queue_vals = {
            'name': self.woo_operation,
            'woo_instance_id': self.woo_instance_id.id,
            'woo_skip_existing_products': self.woo_skip_existing_product,
            "created_by": created_by
        }
        product_queue = woo_product_synced_queue_obj.create(queue_vals)
        return product_queue

    def prepare_product_queue_line_vals(self, product_queue):
        """This method used to prepare a vals for the product data queue line.
            :param product_queue: Record of product queue.
            @return: sync_queue_vals_line
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 13 August 2020.
            Task_id:165892
        """
        sync_queue_vals_line = {
            'woo_instance_id': self.woo_instance_id.id,
            'synced_date': datetime.now(),
            'last_process_date': datetime.now(),
            'queue_id': product_queue.id
        }
        return sync_queue_vals_line

    def woo_export_products(self):
        """ This method use to export selected product in the Woocommerce store.
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 15 September 2020 .
            Task_id: 165897
        """
        woo_product_tmpl_obj = self.env['woo.product.template.ept']
        common_log_book_obj = self.env['common.log.book.ept']
        woo_instance_obj = self.env['woo.instance.ept']
        woo_template_ids = self._context.get('active_ids')

        if not woo_template_ids:
            raise UserError(_("Please select some products to Export to WooCommerce Store."))

        if woo_template_ids and len(woo_template_ids) > 20000:
            raise UserError(_("Error:\n- System will not export more then 20000 Products at a "
                              "time.\n- Please select only 20000 product for export."))

        instances = woo_instance_obj.search([('active', '=', True)])

        woo_product_templates = woo_product_tmpl_obj.search([('id', 'in', woo_template_ids),
                                                             ('exported_in_woo', '=', False)])

        for instance in instances:
            woo_templates = woo_product_templates.filtered(lambda x: x.woo_instance_id == instance)
            if not woo_templates:
                continue
            woo_templates = self.woo_filter_templates(woo_templates)

            common_log_id = common_log_book_obj.woo_create_log_book('export', instance)

            self.import_export_categort_tag(instance, common_log_id)

            woo_product_tmpl_obj.export_products_in_woo(instance, woo_templates,
                                                        self.woo_is_set_price, self.woo_publish,
                                                        self.woo_is_set_image,
                                                        self.woo_basic_detail, common_log_id)
            if common_log_id and not common_log_id.log_lines:
                common_log_id.unlink()

    def import_export_categort_tag(self, instance, common_log_id):
        """ This method is used to import-export the category and tag.
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 6 November 2020 .
            Task_id:168147 - Code refactoring : 5th - 6th November
        """
        common_log_line_obj = self.env['common.log.lines.ept']
        woo_product_categ_obj = self.env['woo.product.categ.ept']
        woo_tags_obj = self.env["woo.tags.ept"]
        woo_process_import_export_obj = self.env["woo.process.import.export"]
        model_id = common_log_line_obj.get_model_id('woo.product.categ.ept')

        domain = [('exported_in_woo', '=', False), ('woo_instance_id', '=', instance.id)]
        not_exported_category = woo_product_categ_obj.search(domain)
        if not_exported_category:
            woo_process_import_export_obj.sync_woo_product_category(instance)
            not_exported_category = woo_product_categ_obj.search(domain)
            not_exported_category and woo_product_categ_obj.export_product_categs(instance, not_exported_category,
                                                                                common_log_id, model_id)
        not_exported_tag = woo_tags_obj.search(domain)
        if not_exported_tag:
            woo_process_import_export_obj.sync_product_tags(instance)
            not_exported_tag = woo_tags_obj.search(domain)
            woo_tags_obj.woo_export_product_tags(instance, not_exported_tag, common_log_id)

    def woo_filter_templates(self, woo_templates):
        """
        This method is used for filter the woo product template based on default_code and woo template id
        :param woo_templates: It contain the woo product templates and Its type is Object
        :return: It will return the browsable object of the woo product template
        """
        filter_templates = []

        for woo_template in woo_templates:
            if not self.env['woo.product.product.ept'].search(
                [('woo_template_id', '=', woo_template.id), ('default_code', '=', False)]):
                filter_templates.append(woo_template)

        return filter_templates

    def import_sale_orders(self, order_type=""):
        """
        Imports woo orders and makes queues for selected instance.
        @author: Maulik Barad on Date 14-Nov-2019.
        Migration done by Haresh Mori @ Emipro on date 1 September 2020 .
        """
        order_queues = self.env['sale.order'].import_woo_orders(self.woo_instance_id,
                                                                self.orders_after_date,
                                                                self.orders_before_date,
                                                                order_type=order_type)
        return order_queues

    def update_order_status(self):
        """ This method used to call child method of update order status.
            @param : self
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 9 September 2020 .
            Task_id: 165894
        """
        self.env['sale.order'].update_woo_order_status(self.woo_instance_id)

    def update_products(self):
        """
        This method is used to update the existing products in woo commerce
        @author: Dipak Gogiya @Emipro Technologies Pvt. Ltd
        Migration done by Haresh Mori @ Emipro on date 19 September 2020 .
        """
        start = time.time()
        woo_instance_obj = self.env['woo.instance.ept']
        common_log_book_obj = self.env['common.log.book.ept']
        woo_product_tmpl_obj = self.env['woo.product.template.ept']

        if not self.woo_basic_detail and not self.woo_is_set_price and not self.woo_is_set_image and not \
            self.woo_publish:
            raise UserError(_('Please Select any one Option for process Update Products'))

        woo_tmpl_ids = self._context.get('active_ids')
        if woo_tmpl_ids and len(woo_tmpl_ids) > 20000:
            raise UserError(_("Error\n- System will not update more then 20000 Products at a "
                              "time.\n- Please select only 20000 product for update."))

        instances = woo_instance_obj.search([('active', '=', True)])
        woo_tmpl_ids = woo_product_tmpl_obj.browse(woo_tmpl_ids)
        for instance in instances:
            woo_templates = woo_tmpl_ids.filtered(lambda x: x.woo_instance_id.id == instance.id and x.exported_in_woo)
            for woo_template in woo_tmpl_ids:
                if woo_template.woo_categ_ids.parent_id:
                    woo_template.woo_categ_ids|=woo_template.woo_categ_ids.parent_id
                    if  woo_template.woo_categ_ids.parent_id.parent_id:
                        woo_template.woo_categ_ids|=woo_template.woo_categ_ids.parent_id.parent_id
                        if  woo_template.woo_categ_ids.parent_id.parent_id.parent_id:
                            woo_template.woo_categ_ids|=woo_template.woo_categ_ids.parent_id.parent_id.parent_id
            if not woo_templates:
                continue
            common_log_id = common_log_book_obj.woo_create_log_book('export', instance)
            if self.woo_basic_detail:
                self.import_export_categort_tag(instance, common_log_id)

            woo_product_tmpl_obj.update_products_in_woo(instance, woo_templates, self.woo_is_set_price,
                                                        self.woo_publish, self.woo_is_set_image, self.woo_basic_detail,
                                                        common_log_id)
            if not common_log_id.log_lines:
                common_log_id.unlink()
        end = time.time()
        _logger.info("Update products in Woocommerce Store in %s seconds.", str(end - start))
        return True

    def export_stock_in_woo(self):
        """ This method use to export stock for selected Woo template.
            @param : self
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 15 September 2020 .
            Task_id: 166453
        """
        woo_instance_obj = self.env['woo.instance.ept']
        woo_product_tmpl_obj = self.env['woo.product.template.ept']
        woo_tmpl_ids = self._context.get('active_ids')

        if woo_tmpl_ids and len(woo_tmpl_ids) > 20000:
            raise UserError(_("Error\n- System will not update more then 20000 Products at a "
                              "time.\n- Please "
                              "select only 20000 product for update."))

        instances = woo_instance_obj.search([('active', '=', True)])
        for instance in instances:
            woo_templates = woo_product_tmpl_obj.search(
                [('woo_instance_id', '=', instance.id), ('id', 'in', woo_tmpl_ids),
                 ('exported_in_woo', '=', True)])
            if not woo_templates:
                continue
            odoo_products = woo_templates.woo_product_ids.mapped('product_id').ids
            woo_product_tmpl_obj.with_context(
                updated_products_in_inventory=odoo_products).woo_update_stock(instance,
                                                                              woo_templates)

    def update_export_category_tags_coupons_in_woo(self):
        """
        This common method will be called from wizard of Update/Export Category and Tags.
        @author: Maulik Barad on Date 14-Dec-2019.
        """
        process_type = self._context.get("process", "")
        if process_type == "update_category":
            self.update_product_categ()
        elif process_type == "export_category":
            self.export_product_categ()
        elif process_type == "update_tags":
            self.update_tags_in_woo()
        elif process_type == "export_tags":
            self.export_tags_in_woo()
        elif process_type == "export_coupon":
            self.export_woo_coupons()
        elif process_type == "update_coupon":
            self.update_woo_coupons()
        return {'type': 'ir.actions.client',
                'tag': 'reload'}

    def export_tags_in_woo(self):
        """
        Exports tags in WooCommerce, which are not exported.
        @author: Maulik Barad on Date 13-Dec-2019.
        """
        woo_tags_obj = self.env["woo.tags.ept"]
        woo_create_log_book = self.env["common.log.book.ept"]
        common_log_book_id = woo_create_log_book.woo_create_log_book('export', self.woo_instance_id)
        if self._context.get("process", "") == "export_tags":
            tags_need_to_export = woo_tags_obj.search(
                [("id", "in", self._context.get("active_ids")), ("exported_in_woo", "=", False)])
        else:
            tags_need_to_export = woo_tags_obj.search(
                [("woo_instance_id", "=", self.woo_instance_id.id), ("exported_in_woo", "=", False)])
        woo_tags_obj.woo_export_product_tags(tags_need_to_export.woo_instance_id,
                                             tags_need_to_export, common_log_book_id)

    def update_tags_in_woo(self):
        """
        Updates tags in WooCommerce, which are not exported.
        @author: Maulik Barad on Date 13-Dec-2019.
        """
        woo_tags_obj = self.env["woo.tags.ept"]
        woo_create_log_book = self.env["common.log.book.ept"]
        common_log_book_id = woo_create_log_book.woo_create_log_book('export', self.woo_instance_id)
        if self._context.get("process", "") == "update_tags":
            tags_need_to_export = woo_tags_obj.search(
                [("id", "in", self._context.get("active_ids")), ("exported_in_woo", "=", True)])
        else:
            tags_need_to_export = woo_tags_obj.search(
                [("woo_instance_id", "=", self.woo_instance_id.id), ("exported_in_woo", "=", True)])
        woo_tags_obj.woo_update_product_tags(tags_need_to_export.woo_instance_id,
                                             tags_need_to_export, common_log_book_id)

    def update_product_categ(self):
        """ This method used to search Woocommerce category for update.
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 13/12/2019.
        """
        product_categ_obj = self.env['woo.product.categ.ept']
        instance_obj = self.env['woo.instance.ept']
        woo_categ_ids = self._context.get('active_ids')

        if woo_categ_ids and self._context.get('process'):
            instances = instance_obj.search([("active", "=", True)])
            for instance in instances:
                woo_product_categs = product_categ_obj.search(
                    [('woo_categ_id', '!=', False), ('woo_instance_id', '=', instance.id),
                     ('exported_in_woo', '=', True), ('id', 'in', woo_categ_ids)])
                woo_product_categs and product_categ_obj.update_product_categs_in_woo(instance,
                                                                                woo_product_categs)
        else:
            woo_product_categs = product_categ_obj.search(
                [('woo_categ_id', '!=', False),
                 ('woo_instance_id', '=', self.woo_instance_id.id),
                 ('exported_in_woo', '=', True)])
            woo_product_categs and product_categ_obj.update_product_categs_in_woo(
                self.woo_instance_id, woo_product_categs)
        return True

    def export_product_categ(self):
        """- This method used to search Woocommerce category for export.
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 14/12/2019.
        """
        common_log_book_obj = self.env["common.log.book.ept"]
        common_log_line_obj = self.env['common.log.lines.ept']
        product_categ_obj = self.env['woo.product.categ.ept']
        instance_obj = self.env['woo.instance.ept']
        model_id = common_log_line_obj.get_model_id("woo.product.categ.ept")
        woo_categ_ids = self._context.get('active_ids')
        # This is called while export product categories from Action
        if woo_categ_ids and self._context.get('process'):
            instances = instance_obj.search([("active", "=", True)])
            for instance in instances:
                woo_product_categs = product_categ_obj.search(
                    [('woo_instance_id', '=', instance.id), ('exported_in_woo', '=', False),
                     ('id', 'in', woo_categ_ids)])
                if woo_product_categs:
                    commom_log_book_id = common_log_book_obj.woo_create_log_book('export', instance)
                    product_categ_obj.export_product_categs(instance, woo_product_categs, commom_log_book_id, model_id)
                    if not commom_log_book_id.log_lines:
                        commom_log_book_id.unlink()
        # This is called while export product categories from WooCommerce Operations
        else:
            woo_product_categs = product_categ_obj.search(
                [('woo_instance_id', '=', self.woo_instance_id.id), ('exported_in_woo', '=', False)])
            if woo_product_categs:
                commom_log_book_id = common_log_book_obj.woo_create_log_book('export', self.woo_instance_id)
                product_categ_obj.export_product_categs(self.woo_instance_id, woo_product_categs, commom_log_book_id,
                                                        model_id)
                if not commom_log_book_id.log_lines:
                    commom_log_book_id.unlink()
        return True

    def import_woo_coupon(self):
        """
        This method is used to import coupons from Woocommerce to Odoo.
        @author: Nilesh Parmar on date 17 Dec 2019.
        """
        """Below method is used to sync the product category from Woocommerce to Odoo"""
        self.sync_woo_product_category()
        common_log_line_obj = self.env['common.log.lines.ept']
        common_log_book_obj = self.env['common.log.book.ept']
        coupons_obj = self.env['woo.coupons.ept']
        model_id = common_log_line_obj.get_model_id("woo.coupons.ept")

        common_log_book_id = common_log_book_obj.woo_create_log_book('import', self.woo_instance_id)
        coupon_queue = coupons_obj.sync_woo_coupons(self.woo_instance_id, common_log_book_id, model_id)

        if not common_log_book_id.log_lines:
            common_log_book_id.unlink()

        return coupon_queue

    def export_woo_coupons(self):
        """
        This methos is used to export coupons from Odoo to Woocommerce store.
        @author: Nilesh Parmar on date 17 Dec 2019.
        """
        common_log_book_obj = self.env["common.log.book.ept"]
        common_log_line_obj = self.env['common.log.lines.ept']
        coupons_obj = self.env['woo.coupons.ept']
        model_id = common_log_line_obj.get_model_id("woo.coupons.ept")
        coupons_ids = self._context.get('active_ids')

        if coupons_ids and self._context.get('process'):
            instances = self.env['woo.instance.ept'].search([("active", "=", True)])
            for instance in instances:
                woo_coupons = coupons_obj.search(
                    [('woo_instance_id', '=', instance.id), ('exported_in_woo', '=', False),
                     ('id', 'in', coupons_ids)])
                if not woo_coupons:
                    continue
                common_log_book_id = common_log_book_obj.woo_create_log_book('export', instance)
                woo_coupons.export_coupons(instance, common_log_book_id, model_id)
                if not common_log_book_id.log_lines:
                    common_log_book_id.unlink()
        else:
            woo_coupons = coupons_obj.search(
                [('woo_instance_id', '=', self.woo_instance_id.id), ('exported_in_woo', '=', False)])
            common_log_book_id = common_log_book_obj.woo_create_log_book('export', self.woo_instance_id)
            if woo_coupons:
                woo_coupons.export_coupons(self.woo_instance_id, common_log_book_id, model_id)
                if not common_log_book_id.log_lines:
                    common_log_book_id.unlink()

    def update_woo_coupons(self):
        """
        This method is used to update coupons from Odoo to Woocommerce store.
        @author: Nilesh Parmar on date 17 Dec 2019.
        """
        coupon_obj = self.env['woo.coupons.ept']
        common_log_book_obj = self.env["common.log.book.ept"]
        model_id = self.env["common.log.lines.ept"].get_model_id("woo.coupons.ept")
        common_log_book_id = common_log_book_obj.woo_create_log_book('export', self.woo_instance_id)

        coupon_ids = self._context.get('active_ids')
        if coupon_ids and self._context.get('process'):
            coupon_ids = coupon_obj.search(
                [('id', 'in', coupon_ids), ('coupon_id', '!=', False), ('exported_in_woo', '=', True)])
        else:
            coupon_ids = coupon_obj.search(
                [('coupon_id', '!=', False), ('woo_instance_id', '=', self.woo_instance_id.id),
                 ('exported_in_woo', '=', True)])

        if coupon_ids:
            coupon_ids.update_woo_coupons(coupon_ids.woo_instance_id, common_log_book_id, model_id)

    def import_products_from_csv(self):
        """
        This method used to import products using CSV file which imported in Woo product layer.
        @author: Dipak Gogiya @Emipro Technologies Pvt. Ltd
        Migration done by Haresh Mori @ Emipro on date 14 September 2020 .
        """
        woo_common_log_obj = self.env["common.log.book.ept"]
        instance_id = self.woo_instance_id

        if not self.choose_file:
            raise UserError(_('Please Select the file for start process of Product Sync'))
        if self.file_name and not self.file_name.lower().endswith('.csv'):
            raise UserError(_("Please provide only CSV File to Import Products"))

        file_data = self.read_csv_file()

        self.csv_required_header_validation(file_data)

        woo_common_log_id = woo_common_log_obj.woo_create_log_book('import', instance_id)
        row_no = 0
        product_tmpl_list = []
        for record in file_data:
            if not record['PRODUCT_TEMPLATE_ID'] or not record['PRODUCT_ID']:
                self.create_csv_mismatch_log_line(record, row_no, woo_common_log_id)
                row_no += 1
                continue

            product_tmpl_id = record['PRODUCT_TEMPLATE_ID']
            if product_tmpl_id not in product_tmpl_list:
                woo_template = self.create_or_update_woo_template(instance_id, record)

            product_tmpl_list.append(product_tmpl_id)

            self.create_or_update_woo_variant(instance_id, record, woo_template)

            row_no += 1

        if not woo_common_log_id.log_lines:
            woo_common_log_id.unlink()

        return True

    def csv_required_header_validation(self, file_data):
        """ This method is used to check the required field is existing in a csv file or not.
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 7 November 2020 .
            Task_id: 168147 - Code refactoring : 5th - 6th November
        """
        required_fields = ['template_name', 'product_name', 'product_default_code',
                           'woo_product_default_code', 'product_description', 'sale_description',
                           'PRODUCT_TEMPLATE_ID', 'PRODUCT_ID', 'CATEGORY_ID']
        for required_field in required_fields:
            if not required_field in file_data.fieldnames:
                raise UserError(_("Required Column %s Is Not Available In CSV File") % required_field)

    def create_csv_mismatch_log_line(self, record, row_no, woo_common_log_id):
        """ This method used to create a mismatch log line while csv processing for import product.
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 7 November 2020 .
            Task_id:168147 - Code refactoring : 5th - 6th November
        """
        common_log_line_obj = self.env["common.log.lines.ept"]
        model_id = common_log_line_obj.get_model_id("woo.process.import.export")
        message = ""
        if not record['PRODUCT_TEMPLATE_ID']:
            if message:
                message += ', \n'
            message += 'Product Template Id not available in Row Number %s' % row_no
        if not record['PRODUCT_ID']:
            if message:
                message += ', \n'
            message += 'Product Id not available in Row Number %s' % row_no
        vals = {
            'message': message,
            'model_id': model_id,
            'log_book_id': woo_common_log_id.id,
        }
        common_log_line_obj.create(vals)

    def read_csv_file(self):
        """
            Read selected .csv file based on delimiter
            @author: Dipak Gogiya @Emipro Technologies Pvt. Ltd
            :return: It will return the object of csv file data
            Migration done by Haresh Mori @ Emipro on date 14 September 2020 .
        """
        self.write({'csv_data': self.choose_file})
        self._cr.commit()
        import_file = BytesIO(base64.decodebytes(self.csv_data))
        file_read = StringIO(import_file.read().decode())
        reader = csv.DictReader(file_read, delimiter=',')
        return reader

    def create_or_update_woo_template(self, instance_id, record):
        """ This method uses to create/update the Woocmmerce layer template.
            @return: woo_template
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 14 September 2020 .
            Task_id: 165896
        """
        product_tmpl_obj = self.env['product.template']
        woo_product_template = self.env['woo.product.template.ept']
        category_obj = self.env['product.category']
        woo_prepare_product_for_export_obj = self.env['woo.prepare.product.for.export.ept']
        woo_category_dict = {}
        woo_template = woo_product_template.search([('woo_instance_id', '=', instance_id.id),
                                                    ('product_tmpl_id', '=', int(record['PRODUCT_TEMPLATE_ID']))])
        product_template = product_tmpl_obj.browse(int(record['PRODUCT_TEMPLATE_ID']))
        if len(product_template.product_variant_ids) == 1:
            product_type = 'simple'
        else:
            product_type = 'variable'

        woo_template_vals = self.preapre_template_vals_from_csv_data(record, instance_id, product_type)

        categ_id = category_obj.browse(int(record.get('CATEGORY_ID'))) if record.get('CATEGORY_ID') else ''

        if categ_id:
            woo_prepare_product_for_export_obj.create_categ_in_woo(categ_id, instance_id.id,
                                                                   woo_category_dict)
            woo_categ_id = woo_prepare_product_for_export_obj.update_category_info(categ_id, instance_id.id)
            woo_template_vals.update({'woo_categ_ids': [(6, 0, woo_categ_id.ids)]})

        if not woo_template:
            woo_template = woo_product_template.create(woo_template_vals)
        else:
            woo_template.write(woo_template_vals)

        # For adding all odoo images into Woo layer.
        woo_prepare_product_for_export_obj.create_woo_template_images(woo_template)

        return woo_template

    def preapre_template_vals_from_csv_data(self, record, instance_id, product_type):
        """ This method is used to prepare a woo template data from CSV file.
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 7 November 2020 .
            Task_id:
        """
        woo_template_vals = {
            'product_tmpl_id': int(record['PRODUCT_TEMPLATE_ID']),
            'woo_instance_id': instance_id.id,
            'name': record['template_name'],
            'woo_product_type': product_type
        }

        if self.env["ir.config_parameter"].sudo().get_param("woo_commerce_ept.set_sales_description"):
            woo_template_vals.update({'woo_description': record.get('sale_description'),
                                      'woo_short_description': record.get('product_description')})
        return woo_template_vals

    def create_or_update_woo_variant(self, instance_id, record, woo_template):
        """ This method uses to create/update the Woocmmerce layer variant.
            @return: woo_template
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 14 September 2020 .
            Task_id: 165896
        """
        woo_product_obj = self.env['woo.product.product.ept']
        woo_prepare_product_for_export_obj = self.env['woo.prepare.product.for.export.ept']
        woo_variant = woo_product_obj.search(
            [('woo_instance_id', '=', instance_id.id), ('product_id', '=', int(record['PRODUCT_ID'])),
             ('woo_template_id', '=', woo_template.id)])

        woo_variant_vals = ({
            'woo_instance_id': instance_id.id,
            'product_id': int(record['PRODUCT_ID']),
            'woo_template_id': woo_template.id,
            'default_code': record['woo_product_default_code'],
            'name': record['product_name'],
        })

        if not woo_variant:
            woo_variant = woo_product_obj.create(woo_variant_vals)
        else:
            woo_variant.write(woo_variant_vals)

        # For adding all odoo images into Woo layer.
        woo_prepare_product_for_export_obj.create_woo_variant_images(woo_template.id, woo_variant)

        return woo_variant

    def woo_check_running_schedulers(self, cron_xml_id):
        """ This method is used to check that seleted operation cron is running or not.
            :param cron_xml_id: Xml id of the scheduler action.
            @author: Haresh Mori @Emipro Technologies Pvt. Ltd on date 5 November 2020 .
            Task_id: 167715
        """
        try:
            cron_id = self.env.ref('woo_commerce_ept.%s%d' % (cron_xml_id, self.woo_instance_id.id))
        except:
            return
        if cron_id and cron_id.sudo().active:
            res = cron_id.try_cron_lock()
            if res == None:
                res = {}
            if res and res.get('reason') or res.get('result') == 0:
                message = "You are not allowed to run this process.The Scheduler is already started the Process."
                self.cron_process_notification = message
                self.is_hide_execute_button = True
            if res and res.get('result'):
                self.cron_process_notification = "This process is also performed by a scheduler, and the next " \
                                                 "schedule for this process will run in %s minutes." % res.get('result')
            elif res and res.get('reason'):
                self.cron_process_notification = res.get('reason')


import functools
import json
import logging
from tornado.web import MissingArgumentError
from torndsession.sessionhandler import SessionBaseHandler
from models.dao import Dao
from models.admin import FFAdmin

__author__ = 'Siglud'

class BaseHandler(SessionBaseHandler):
    def data_received(self, chunk):
        pass

    def initialize(self):
        """初始化数据库连接"""
        self.__angular_body_argument = None
        Dao.create_mysql_session()

    def on_finish(self):
        """关闭数据库连接"""
        Dao.close_mysql_session()

    def get_current_user(self):
        uid = self.session.get('uid', '')
        return FFAdmin(user_id=uid)

    def prepare(self):
        """请求前的操作，检查是否有登录"""
        if not self.get_current_user().exists and self.request.uri != '/login/':
            self.redirect('/login/')
            return

    def get_angular_argument(self, name):
        """获取angular传过来的参数"""
        if not self.request.body:
            raise MissingArgumentError(name)
        if not self.__angular_body_argument:
            try:
                self.__angular_body_argument = json.loads(self.request.body.decode('utf-8'))
            except (ValueError, TypeError):
                raise MissingArgumentError(name)
        return self.__angular_body_argument.get(name)

    def on_success(self, data=None):
        """正确的返回"""
        self.write(dict(
            ret=0,
            msg='ok',
            data=data if data else ''
        ))

    def on_error(self, code, msg):
        """错误的返回"""
        self.write(dict(
            ret=code,
            msg=msg,
        ))

    def logger(self):
        return logging.getLogger()


from flask import Flask, render_template, request, session, redirect, url_for

app = Flask(__name__)
app.secret_key = 'key'

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        study = int(request.form['study'])
        rest = int(request.form['rest'])
        sets = int(request.form['sets'])

        session['study'] = study * 60
        session['rest'] = rest * 60
        session['sets'] = sets
        session['set_counter'] = 0

        return redirect(url_for('study'))

    return render_template('index.html')

@app.route('/study')
def study():
    if session['set_counter'] == session['sets']:
        return redirect(url_for('completed'))

    session['set_counter'] += 1
    return render_template('index.html', study=session['study'], sets=session['set_counter'])

@app.route('/break')
def rest():
    return render_template('index.html', rest=session['rest'], sets=session['set_counter'])

@app.route('/complete')
def completed():
    return render_template('index.html', sets=session['set_counter'])

if __name__ == '__main__':
    app.run(port=5000)


# -*- coding:utf-8 -*-

# TensorFlow 入门（三）多层 CNNs 实现 mnist 分类
# 在前面简单全连接网络的基础上，本例子主要介绍怎么用 TensorFlow 来写一个卷积层。
# 然后计算损失，梯度，优化器和前面简单全连接网络没有什么区别。可直接参考官方教程。
# 此外，我添加了查看网络中间层权值的代码。

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.examples.tutorials.mnist import input_data

config = tf.ConfigProto()
config.gpu_options.allow_growth = True
sess = tf.Session( config=config )

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

def weight_variable( shape ):
    initial = tf.truncated_normal( shape, stddev=0.1 )
    return tf.Variable( initial )

def bias_variable( shape ):
    initial = tf.constant( 0.1, shape=shape )
    return tf.Variable( initial )

def conv2d( x, w ):
    # input:[batch, in_height, in_width, in_channels]
    # filter:[filter_height, filter_width, in_channels, out_channels]
    # strides:[1, height, width, 1]
    return tf.nn.conv2d( x, w, strides=[1,1,1,1], padding='SAME' )

def max_pool_2x2( x ):
    return tf.nn.max_pool( x, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME' )

def main():
    mnist = input_data.read_data_sets( 'MNIST_data', one_hot=True )

    # None indicates that the first dimension, corresponding to the batch size, can be of any size.
    x_ = tf.placeholder( tf.float32, [None,784] )
    y_ = tf.placeholder( tf.float32, [None, 10] )

    # 把X转为卷积所需要的形式,[batch, in_height, in_width, in_channels]
    x = tf.reshape( x_, [-1, 28, 28, 1] )

    # 第一层卷积：5×5×1卷积核32个 [5，5，1，32],h_conv1.shape=[-1, 28, 28, 32]
    w_conv1 = weight_variable( [5,5,1,32] )
    b_conv1 = bias_variable( [32] )
    h_conv1 = tf.nn.relu( conv2d( x, w_conv1 ) + b_conv1 )

    # 第一个pooling 层[-1, 28, 28, 32] -> [-1, 14, 14, 32]
    h_pool1 = max_pool_2x2( h_conv1 )

    # 第二层卷积：5×5×32卷积核64个 [5，5，32，64],h_conv2.shape=[-1, 14, 14, 64]
    w_conv2 = weight_variable( [5,5,32,64] )
    b_conv2 = bias_variable( [64] )
    h_conv2 = tf.nn.relu( conv2d( h_pool1, w_conv2 ) + b_conv2 )

    # 第二个pooling 层,[-1, 14, 14, 64]->[-1, 7, 7, 64]
    h_pool2 = max_pool_2x2( h_conv2 )

    h_pool2_flat = tf.reshape( h_pool2, [-1, 7*7*64] )

    # fc1
    w_fc1 = weight_variable( [7*7*64, 1024] )
    b_fc1 = bias_variable( [1024] )
    h_fc1 = tf.nn.relu( tf.matmul( h_pool2_flat, w_fc1 ) + b_fc1 )

    # dropout: 输出的维度和h_fc1一样，只是随机部分值被值为零
    keep_prob = tf.placeholder( tf.float32 )
    h_fc1_drop = tf.nn.dropout( h_fc1, keep_prob )

    # 输出层
    W_fc2 = weight_variable([1024, 10])
    b_fc2 = bias_variable([10])
    y_pre = tf.nn.softmax( tf.matmul(h_fc1_drop, W_fc2) + b_fc2 )

    cross_entropy = -tf.reduce_sum(y_ * tf.log(y_pre))
    train = tf.train.AdamOptimizer( 1e-4 ).minimize( cross_entropy )

    #　预测值中最大值（１）即分类结果，是否等于原始标签中的（１）的位置。argmax()取最大值所在的下标
    correct_prediction = tf.equal(tf.argmax(y_pre, 1), tf.arg_max(y_, 1))
    accuracy = tf.reduce_mean( tf.cast(correct_prediction, tf.float32) )

    # 如果一次性来做测试的话，可能占用的显存会比较多，所以测试的时候也可以设置较小的batch来看准确率
    test_acc_sum = tf.Variable( 0, dtype=tf.float32 )
    batch_acc = tf.placeholder( tf.float32 )
    update = tf.assign( test_acc_sum, tf.add( test_acc_sum, batch_acc ) )

    sess = tf.InteractiveSession()
    sess.run( tf.global_variables_initializer() )

    # 训练
    for i in range( 5000 ):
        # X_batch.shape=[-1,28*28], y_batch.shape=[-1,10]
        X_batch, y_batch = mnist.train.next_batch( batch_size=50 )
        if i % 500 == 0:
            train_accuracy = accuracy.eval( feed_dict={x_: X_batch, y_: y_batch, keep_prob: 1.0} )
            print( "step %d, training acc %g" % (i, train_accuracy) )
        train.run( feed_dict={x_: X_batch, y_: y_batch, keep_prob: 0.5} )

    # 全部训练完了再做测试，batch_size=100
    for i in range( 100 ):
        X_batch, y_batch = mnist.test.next_batch( batch_size=100 )
        test_acc = accuracy.eval( feed_dict={x_: X_batch, y_: y_batch, keep_prob: 1.0} )
        update.eval( feed_dict={batch_acc: test_acc} )
        if (i+1) % 20 == 0:
            print( "testing step %d, test_acc_sum %g" % (i+1, test_acc_sum.eval()) )
    print( " test_accuracy %g" % (test_acc_sum.eval() / 100.0) )

    # x_img = mnist.train.images[2].reshape([-1,784])
    # y_img = mnist.train.labels[2].reshape([-1,10])
    # result = h_conv2.eval( feed_dict={ x_:x_img, y_:y_img, keep_prob:1 } )

    # for i in range( 32 ):
    #     show_img = result[:,:,:,i]
    #     show_img.shape = [ 14,14 ]
    #     plt.subplot( 4,8,i+1 )
    #     plt.imshow( show_img, cmap='gray' )
    #     plt.axis('off')
    # plt.show()

    # img = mnist.train.images[2]
    # img.shape = [ 28,28 ]
    # plt.imshow( img, cmap='gray' )

    # plt.show()

if __name__ == '__main__' :
    main()
    # mnist = input_data.read_data_sets( 'MNIST_data', one_hot=True )

    # img1 = mnist.train.images[1]
    # label1 = mnist.train.labels[1]
    # img1.shape = [ 28, 28 ]
    # print( label1 )
    # print( 'img_data shape = ', img1.shape )

    # plt.imshow( img1, cmap='gray' )
    # plt.axis( 'off' )
    # plt.show()


#!/usr/bin/env python

from radical.entk import Pipeline, Stage, Task, AppManager
from glob import glob
from subprocess import Popen, PIPE
from os import linesep, environ, path as op

ssh = "gsissh -p 2222 bridges.psc.xsede.org"
dir_ = "/pylon5/mc3bggp/vhayot/bb_blocks"
out_dir = "/pylon5/mc3bggp/vhayot/inc_out"
iterations = 10

if environ.get('RADICAL_ENTK_VERBOSE') == None:
    environ['RADICAL_ENTK_REPORT'] = 'True'

# Description of how the RabbitMQ process is accessible
# No need to change/set any variables if you installed RabbitMQ has a system
# process. If you are running RabbitMQ under a docker container or another
# VM, set "RMQ_HOSTNAME" and "RMQ_PORT" in the session where you are running
# this script.
hostname = environ.get('RMQ_HOSTNAME', 'localhost')
port = environ.get('RMQ_PORT', 5672)

def main():

    cmd = "{0} 'ls {1}'".format(ssh, dir_)
    p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
    out,_ = p.communicate()

    out = out.decode('utf-8').strip().split(linesep)

    fullpaths = [op.join(dir_, p) for p in out]
    print(fullpaths)

    # Start radical entk pipeline

    p = Pipeline()

    for i in range(iterations):

        s = Stage()

        for fp in fullpaths:

            t = Task()
            t.name = 'Incrementation {}'.format(i)
            t.pre_exec = ['source /home/vhayot/miniconda3/etc/profile.d/conda.sh', 'conda activate radenv']
            t.executable = 'python /home/vhayot/inc.py'

            if i == 0:
                t.arguments = [fp, out_dir, i]
            else:
                # Note: assuming all data is accessible through shared dir
                # radical entk functions without sharedfs, however
                t.arguments = [op.join(out_dir, "it-{0}-{1}".format(i-1, op.basename(fp))), out_dir, i]

            s.add_tasks(t)

        # Create a new stage everytime there's a dependency
        p.add_stages(s)

    appman = AppManager(hostname=hostname, port=port)

    appman.resource_desc = {
        'resource': 'xsede.bridges',
        'walltime': 20,
        'cpus': 5,
        'project': 'mc3bggp',
        'schema': 'gsissh'
    }

    appman.workflow = set([p])

    appman.run()

if __name__ == '__main__':
    main()


'''
Write a program with 3 functions. Each function must call
at least one other function and use the return value to do something.

'''

def age_count(years):
    # takes years, calls a function to return minutes and returns seconds
    seconds = age_count_2(years)*60
    return seconds

def age_count_2(yars):
    # takes years and returns minutes
    minutes = yars * 365 * 24
    return minutes

def init(name):
    age = int(input(f'What\'s your age, {name}? '))
    print(f'So, you lived for {age} years, or {age_count(age)} seconds')
    yes_or_no = input('Pretty old, huh? yes/no?')
    i = 0
    while yes_or_no.lower() != 'yes':
        print(f'Don\'t agree? Let me remind you, you\'re {age_count(age)} seconds old')
        yes_or_no = input('Pretty old, huh? yes/no?')
        i += 1
        if i > 4:
            print('Hard to persuade you, huh')
            break
    if yes_or_no.lower() == 'yes':
        print(f'Bye, {name}, my old friend')

user_name = input('Hello! What\'s your name?')
init(user_name)


# encoding: utf-8

import tushare as ts
import pickle

# 获取股票列表
stock_basics = ts.get_stock_basics()

# 循环获取股票历史行情
stock_hist_data = {}
start_dt = '2015-01-01'
end_dt = '2018-06-30'

counter = 0
for code in stock_basics.index.tolist():
    counter += 1
    print(counter)
    stock_hist_data[code] = ts.get_hist_data(code, start=start_dt, end=end_dt)

with open('./stock_hist_data.pkl', 'wb') as fw:
    pickle.dump(stock_hist_data, file=fw)

with open('./stock_basics.pkl', 'wb') as fw:
    pickle.dump(stock_basics, file=fw)

# file_to_read = open('./stock_hist_data.pkl', 'rb')
# res = pickle.load(file_to_read)


# Local import
import dbus
from dbusitem import Dbusitem
import tracing

class DbusDevice(object):
	## The constructor processes the tree of dbus-items.
	# @param bus Session/System bus object
	# @param name the dbus-service-name.
	def __init__(self, bus, name, eventCallback):
		self._dbus_name = name
		self._dbus_conn = bus
		self._items = []
		self._eventCallback = eventCallback
		self._getChildren(bus, name)
		self._service_id = self._dbus_conn.get_name_owner(name)

	def __del__(self):
		tracing.log.debug('__del__ %s' % self)
		self._dbus_name = None
		self._value = None
		self._eventCallback = None

	def _getChildren(self, bus, service):
		data = self._dbus_conn.call_blocking(service, '/', None, 'GetValue', '', [])
		for child in data:
			name = "/" + child
			self._items.append(name)
		self._dbus_conn.add_signal_receiver(self._on_dbus_value_changed,
			dbus_interface='com.victronenergy.BusItem', signal_name='PropertiesChanged', path_keyword='path',
			sender_keyword='service_id')

	def _on_dbus_value_changed(self, changes, path=None, service_id=None):
		if service_id != None and service_id == self._service_id:
			self._eventCallback(self._dbus_name, path, changes)

	## Returns the dbus-service-name which represents the Victron-device.
	def __str__(self):
		return "DbusDevice=%s" % self._dbus_name

	def getBusName(self):
		return self._dbus_name

	def getValues(self):
		values = {}
		for i in self._items:
			properties = {}
			properties['Value'] = self._dbus_conn.call_blocking(self._dbus_name, i, None, 'GetValue', '', [])
			properties['Valid'] = bool(properties['Value'] != dbus.Array([]))
			properties['Text'] = str(self._dbus_conn.call_blocking(self._dbus_name, i, None, 'GetText', '', []))
			values[i] = properties
		return values

# convert to python type.
# pickle doesn't handle dbus-types.
def dbusTypeToPythonType(obj_path, dbusValue):
	pythonValue = dbusValue
	dbusType = type(dbusValue).__name__
	if dbusType == dbus.UInt16 or dbusType == dbus.UInt32 or dbusType == dbus.UInt64:
		pythonValue = int(dbusValue)
	elif dbusType == dbus.Byte or dbusType == dbus.Int16 or dbusType == dbus.Int32 or dbusType == dbus.Int64:
		pythonValue = int(dbusValue)
	elif dbusType == 'Double':
		pythonValue == float(dbusValue)
	elif dbusType == dbus.String:
		pythonValue == str(dbusValue)
	if pythonValue == -1:
		if obj_path == '/Ac/ActiveIn/L1/V':
			tracing.log.info("unknown %s %s %s" % (obj_path, dbusType, dbusValue))
	return pythonValue


class Solution(object):
    def decode(self, encoded, first):
        """
        :type encoded: List[int]
        :type first: int
        :rtype: List[int]
        """
        current = first
        result = [first]
        for encode in encoded:
            nextVal = current ^ encode
            result.append(nextVal)
            current = nextVal
        return result