I want to print out an invoice(pdf) automatically, what's recently saved on the server. And also making manual saving possible
I'm using prestashop 1.6.1 and the invoices are mostly downloaded from the prestashop admin page, but I needed more easier way to print out these invoices, so I made an adminpage for myself it looks like this:
The printer button has a href of the invoice generated address
like:"http://www.example.com/admin/index.php?controller=AdminPdf&submitAction=generateInvoicePDF&id_order=3230"
From the link I can download it and then print it when it's opened in pdf reader, but I want to do this in one click.
Soo... I made an script for automatically printing the pdf when its saved on some specific location
#! /usr/bin/python import os
import os
import time
import os.path
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
class ExampleHandler(FileSystemEventHandler):
def on_created(self, event):
output=str(event.src_path.replace("./",""))
print(output)
#print event.src_path.replace("./","")
print "Got event for file %s" % event.src_path
os.system("lp -d HL2250DN %s" % output)
observer = Observer()
event_handler = ExampleHandler()
observer.schedule(event_handler, path='.',recursive=False)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
There is two options to download it automatically to the server
1. Override PDF.php and PDFGenerator.php files like this:
PDF.php
class PDF extends PDFCore
{
public function render($display = true)
{
if($this->template == PDF::TEMPLATE_INVOICE)
parent::render('F', true);
return parent::render($display);
}
}
?>
PDFGenerator.php
<?php
class PDFGenerator extends PDFGeneratorCore
{
public function render($filename, $display = true)
{
if (empty($filename)) {
throw new PrestaShopException('Missing filename.');
}
$this->lastPage();
if ($display === true) {
$output = 'D';
} elseif ($display === false) {
$output = 'S';
} elseif ($display == 'D') {
$output = 'D';
} elseif ($display == 'S') {
$output = 'S';
} elseif ($display == 'F') {
$output = 'F';
$filename = '/folder/for/print_it/'.str_replace("#", "", $filename);
} else {
$output = 'I';
}
return $this->output($filename, $output);
}
}
?>
2. Use script to download
First attempt
The first option worked for automatic saving, but when I tried to save invoices manually I got an blank or broken pdf file. I also tried to change the pdf.php, but it dident work out for me. Also made an post about this: Prestashop saving invoices manually and automatically. No answers were given and I moved on second option.
Second attempt
I tried to download invoices with python script and it worked, but how can I know which one to download?
#!/usr/bin/env python
import requests
import webbrowser
url = "http://www.example.com/admin/index.php?controller=AdminLogin&token=5a01dc4e606bca6c26e95ddea92d3d15"
url2 = "http://www.example.com/admin/index.php?controller=AdminPdf&token=35b276c05aa6f5eb516737a8d534eb66&submitAction=generateInvoicePDF&id_order=3221"
payload = {'example': 'example',
'example': 'example',
'stay_logged_in':'2',
'submitLogin':'1',}
with requests.session() as s:
# fetch the login page
s.get(url)
# post to the login form
r = s.post(url, data=payload)
print(r.text)
response = s.get(url2)
with open('/tmp/metadataa.pdf', 'wb') as f:
f.write(response.content)
Soo the problem with this option is that.. How can I pass the href(what was clicked from the printer button) to url?
Solving this has been really frustrating and I know there is an simple and easy option for this, but I'm still looking for this.
Everytime you generate invoice PDF you are forcing it to be saved as local file.
What you want to do is add an extra GET parameter to the print button and check for its presence in the overriden class so that the PDF only gets stored as local file when you want to print directly.
So first add a GET parameter to print buttons eg. &print=1. Either in your template or wherever you are generating these buttons so that the button's href looks like this:
http://www.example.com/admin/index.php?controller=AdminPdf&submitAction=generateInvoicePDF&id_order=3230&print=1
Now you can check if parameter exists in PDF class and only then force the PDF to be outputted to local file.
class PDF extends PDFCore
{
public function render($display = true)
{
if($this->template == PDF::TEMPLATE_INVOICE && Tools::getValue('print') == 1) {
// Output PDF to local file
parent::render('F');
// Redirect back to the same page so you don't get blank page
Tools::redirectAdmin(Context::getContext()->link->getAdminLink('AdminMyController'));
}
else {
return parent::render($display);
}
}
}
You can keep the overriden PDFGenerator class as is.
Related
I've been getting this problem for a little while now.
The thing is that i have an HTML form proceed by PHP which looks like that:
<?php
if (isset($_POST)) {
$link = mysqli_connect("localhost", "root", "password", "tablename");
$url = $_POST['url'];
$shorturl = str_replace(['/', 'https:', 'http:'], '', $url);
$iconpath = shell_exec("python3 /home/favicon.py {$url}");
$sql = "INSERT INTO links (url, shorturl, iconpath) values ('{$url}', '{$shorturl}', '{$iconpath}')";
$result = mysqli_query($link, $sql);
}
/*
header('Location: /');
exit;
*/
?>
This code is supposed to extract the given URL from the form, execute python file that downloads favicon of the site and insert the data into a MySQL table.Python code:
import sys
import requests
url = sys.argv[1]
img_data = requests.get(f'{url}/favicon.ico').content
iconpath = '/home/favicon.png'
with open(iconpath, 'wb') as handler:
handler.write(img_data)
print(iconpath)
It all works fine except for the favicon part. When i run the python file from shell, it works fine. When i run it from PHP interactive console by the exact same code written in the form handler, it works fine. But it just won't run properly in the handler, because even when i try to debug it like
echo $iconpath;
it doesn't actually show anything in there. What can i do with it?
P.S. the code actually inserts $url and $shorturl variables into the database, so i said it all works fine except the shell_exec part
I'm working on creating a JupyterLab server-side extension from this template and am having trouble calling an imported python function in the post method of handlers.py. The post request is sent from my index.ts file with a body containing the relative path of the active notebook when the user presses the "Measure Energy Usage" button. Sending it works fine if I leave out the call to measure_cell2.measure() in handlers.py. However, when I try to call that function, I get these errors on the right from the post request:
In the terminal running jupyter lab, I get this error:
[W 2021-07-13 12:42:47.633 ServerApp] 404 POST /jlab-ext-example/hello?1626198167480 (127.0.0.1) 7.70ms referer=http://localhost:8888/lab/tree/jupyter_lab_ext/jlab_ext_example/nbtest2.ipynb
I know that abs_path is the correct path, because when I leave out the measure function call in handlers.py, simply print the path returned by os.path.abspath, and then run the measure function directly from the python console or the terminal using that path, it produces the desired output. The post method in handlers.py doesn't seem to be executing at all since print(abs_path) is never executed and it comes before the call to measure. What could be causing this error?
JupyterLab 3.0.16,
Ubuntu 18.04.5 LTS (GNU/Linux 4.15.0-143-generic x86_64),
Python 3.9.5,
Node v14.8.0,
tsc 2.7.2
index.ts:
import {
ILabShell,
JupyterFrontEnd,
JupyterFrontEndPlugin
} from '#jupyterlab/application';
import { IRetroShell } from '#retrolab/application';
import { ICommandPalette } from '#jupyterlab/apputils';
import { ILauncher } from '#jupyterlab/launcher';
import { requestAPI } from './handler';
import { ToolbarButton } from '#jupyterlab/apputils';
import { DocumentRegistry } from '#jupyterlab/docregistry';
import { INotebookModel, NotebookPanel } from '#jupyterlab/notebook';
import { IDisposable } from '#lumino/disposable';
import { Title, Widget } from '#lumino/widgets';
var nbPath: string; // Holds relative path of notebook to convert
// Create button on the toolbar
export class ButtonExtension implements DocumentRegistry.IWidgetExtension<NotebookPanel, INotebookModel> {
constructor(app: JupyterFrontEnd) {
this.app = app;
}
readonly app: JupyterFrontEnd
// Create the toolbar button
createNew(panel: NotebookPanel, context: DocumentRegistry.IContext<INotebookModel>): IDisposable {
let mybutton = new ToolbarButton({
label: 'Measure Energy Usage',
onClick: async () => {
// Post request to Jupyter server containing relative
// path to .ipynb file
const dataToSend = { file: nbPath };
try {
const reply = await requestAPI<any>('hello', {
body: JSON.stringify(dataToSend),
method: 'POST'
});
console.log(reply);
} catch (reason) {
console.error(
`Error on POST /jlab-ext-example/hello ${dataToSend}.\n${reason}`
);
}
}
});
// Add the toolbar button to the notebook toolbar
panel.toolbar.insertItem(10, 'MeasureEnergyUsage', mybutton);
console.log("MeasEnerUsage activated");
// The ToolbarButton class implements `IDisposable`, so the
// button *is* the extension for the purposes of this method.
return mybutton;
}
}
/**
* Initialization data for the server-extension-example extension.
*/
const extension: JupyterFrontEndPlugin<void> = {
id: 'server-extension-example',
autoStart: true,
optional: [ILauncher],
requires: [ICommandPalette],
activate: async (
app: JupyterFrontEnd
) => {
console.log('JupyterLab extension server-extension-example is activated!');
const your_button = new ButtonExtension(app);
app.docRegistry.addWidgetExtension('Notebook', your_button);
// Get name and relative path of active notebook tab
var shell = app.shell as ILabShell | IRetroShell;
// When user changes tabs, update nbPath to be the relative path for current notebook
const onTitleChanged = (title: Title<Widget>) => {
nbPath = title.caption;
nbPath = nbPath.slice(nbPath.indexOf("Path: ") + 6, nbPath.indexOf("Last Saved") - 1);
console.log(nbPath);
};
// Watch for user changing tabs in JupyterLab
shell.currentChanged.connect((_: any, change: any) => {
const { oldValue, newValue } = change;
if (oldValue) {
oldValue.title.changed.disconnect(onTitleChanged);
}
if (newValue) {
newValue.title.changed.connect(onTitleChanged);
}
});
}
};
export default extension;
handlers.py:
import os
import json
import subprocess
from notebook.base.handlers import APIHandler
from notebook.utils import url_path_join
import tornado
from tornado.web import StaticFileHandler
import measure_cell2
class RouteHandler(APIHandler):
# The following decorator should be present on all verb methods (head, get, post,
# patch, put, delete, options) to ensure only authorized user can request the
# Jupyter server
#tornado.web.authenticated
def get(self):
self.finish(json.dumps({"data": "At the /jlab-ext-example/hello endpoint; finding and converting notebook"}))
#tornado.web.authenticated
def post(self):
# receive .ipynb file name and relative path from index.ts on client-side
# input_data is a dictionary with a key "file"
input_data = self.get_json_body()
# convert notebook to .py file with nbconvert
subprocess.run(["jupyter", "nbconvert", input_data["file"], "--to", "script"])
# get name and absolute path of converted .py file
python_file_name = input_data["file"]
extension_index = python_file_name.find(".")
python_file_name = python_file_name[0:extension_index] + ".py"
abs_path = os.path.abspath(python_file_name)
print(abs_path)
# measure code energy usage
measure_cell2.measure(abs_path)
# confirm conversion and measurement occurred
data = {"greetings": "Converted notebook to the python file {}; now measuring energy usage".format(python_file_name)}
self.finish(json.dumps(data))
def setup_handlers(web_app, url_path):
host_pattern = ".*$"
base_url = web_app.settings["base_url"]
# Prepend the base_url so that it works in a JupyterHub setting
route_pattern = url_path_join(base_url, url_path, "hello")
handlers = [(route_pattern, RouteHandler)]
web_app.add_handlers(host_pattern, handlers)
# Prepend the base_url so that it works in a JupyterHub setting
doc_url = url_path_join(base_url, url_path, "public")
doc_dir = os.getenv(
"JLAB_SERVER_EXAMPLE_STATIC_DIR",
os.path.join(os.path.dirname(__file__), "public"),
)
handlers = [("{}/(.*)".format(doc_url), StaticFileHandler, {"path": doc_dir})]
web_app.add_handlers(".*$", handlers)
measure_cell2.py:
import requests
def measure(file_path):
base_url = 'http://localhost:9898'
# send file and get ID
url_id = base_url + '/id'
print(file_path)
files = {'file': open(file_path, 'rb')} # opens file into buffer; rb = read buffer
getID = requests.post(url_id, files=files)
ID = getID.json().get('id')
print("Running Code at ", file_path)
print(ID)
# send ID and get gpu results
url_results_gpu = base_url + '/results/gpu?id={}'.format(ID)
gpu_results = requests.get(url_results_gpu)
print(gpu_results.text)
# send ID and get cpu results
url_results_cpu = base_url + '/results/cpu?id={}'.format(ID)
cpu_results = requests.get(url_results_cpu)
print(cpu_results.text)
I would like to download multiple images from thispersondoesnotexist.com and save them in a Windows folder. The site uses an AI StyleGAN to generate thousands of face images, but the problem is that the site only generates one image per view, which is labelled as image.jpg, and this single image changes every time the page is reset.
I would like to write a Python script that retrieves and saves multiple instances of this randomly generated image, ending up with a number of different images.
I tried using the following script written by Nandhugp:
import urllib.request
import random
n=input("How many images do you need?")
val=int(n)
dir=input("Enter the directory you want to save")
for i in range(val):
file_name = random.randrange(1,10000)
full_file_name = dir + str(file_name) + '.jpg' #Insert your
def downloader(image_url,full_file_name):
urllib.request.urlretrieve(image_url,full_file_name)
downloader("https://www.thispersondoesnotexist.com/",full_file_name)
However, the script doesn't work for me; I'm sorry but I'm new to Python 3 and am also having some difficulty understanding file paths in Windows. When the script asks for the directory I want to save the files in, do I enter "c:\faces\" or "c:/faces/"?
I'm using Win 7 64-bit OS on an older laptop.
# python3
import requests
def download(fileName):
f = open(fileName,'wb')
f.write(requests.get('https://thispersondoesnotexist.com/image', headers={'User-Agent': 'My User Agent 1.0'}).content)
f.close()
for i in range(2000):
download(str(i)+'.jpg')
//node js
var request = require('request');
var fs = require('fs');
var sleep = function (duration) {
return new Promise(resolve => {
setTimeout(() => resolve(), duration)
});
}
var downloadFile = function (url, fileName) {
return new Promise(resolve => {
var req = request(url);
var file = fs.createWriteStream(fileName);
req.pipe(file);
req.on('end', () => {
resolve();
})
})
}
var main = async function () {
for (var i = 0; i < 100; i++) {
console.log('Downloading ' + i)
await downloadFile('https://thispersondoesnotexist.com/image', `${i}.jpg`)
await sleep(1000);
}
}
main();
If you were using Linux or Cygwin on Windows, you could just run this:
watch -n6 wget https://thispersondoesnotexist.com/image
I tried to upload video file using python, the problem is the system cannot find the file even though i write the path of file. my code is like this:
import os
import requests
#step 1
host = 'https://blablabla.com'
test = {
"upload_phase" : "start",
"file_size" : 1063565
}
params = {
"access_token":my_access_token,
"fields":"video_id, start_offset, end_offset, upload_session_id",
}
vids = requests.post(host, params=params, data=test)
vids = vids.json()
try:
video_id= vids["video_id"],
start_offset= vids["start_offset"],
end_offset= vids["end_offset"],
upload_session_id= vids["upload_session_id"]
except:
pass
print(vids)
###############################################################################
#step 2
###############################################################################
test = {
"upload_phase" : "transfer",
"start_offset" : start_offset,
"upload_session_id": upload_session_id,
"video_file_chunk": os.path.realpath('/home/def/Videos/test.mp4')
}
params = {
"access_token":my_access_token,
"fields":"start_offset, end_offset",
}
vids = requests.post(host, params=params, data=test)
vids = vids.json()
try:
start_offset= vids["start_offset"],
end_offset= vids["end_offset"]
except:
pass
print(vids)
Many way i tried, like os.path.abspath, os.path, os.path.dirname, os.path.basename, os.path.isfile, os.path.isabs, os.path.isdir it's still doesn't work. even i give import os.path or import os.
In your code you just send path to your file as the string to server, but not file itself. You should try something like:
my_file = {'file_to_upload': open(os.path.realpath('/home/def/Videos/test.mp4'),'rb')}
# You should replace 'file_to_upload' with the name server actually expect to receive
# If you don't know what server expect to get, check browser's devconsole while uploading file manually
vids = requests.post(host, params=params, files=my_file)
Also note that you might need to use requests.Session() to be able to handle cookies, access token...
I'm using Selenium to run tests in Chrome via the Python API bindings, and I'm having trouble figuring out how to configure Chrome to make the console.log output from the loaded test available. I see that there are get_log() and log_types() methods on the WebDriver object, and I've seen Get chrome's console log which shows how to do things in Java. But I don't see an equivalent of Java's LoggingPreferences type in the Python API. Is there some way to accomplish what I need?
Ok, finally figured it out:
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
# enable browser logging
d = DesiredCapabilities.CHROME
d['loggingPrefs'] = { 'browser':'ALL' }
driver = webdriver.Chrome(desired_capabilities=d)
# load the desired webpage
driver.get('http://foo.com')
# print messages
for entry in driver.get_log('browser'):
print(entry)
Entries whose source field equals 'console-api' correspond to console messages, and the message itself is stored in the message field.
Starting from chromedriver, 75.0.3770.8, you have to use goog:loggingPrefs instead of loggingPrefs:
d['goog:loggingPrefs'] = { 'browser':'ALL' }
To complete the answer: starting from chromedriver 75.0.3770.8, you have to use goog:loggingPrefs instead of loggingPrefs.
See Chromedriver changelog: http://chromedriver.chromium.org/downloads or this bug: https://bugs.chromium.org/p/chromedriver/issues/detail?id=2976
if you are using the python logging module (and you should be)... here is a way to add the selenium browser logs to the python logging system..
the get_browser_log_entries() function grabs the logs from eth provded driver, emits them to the python logging module as chrome. (ie chrome.console-api, chrome.network etc..) using the timestamp from the browser.(in case there is a delay before you call get_log)
it could probably do with some better exception handling (like if logging is not turned on ) etc.. but it works most of the time..
hop
import logging
from selenium import webdriver
def get_browser_log_entries(driver):
"""get log entreies from selenium and add to python logger before returning"""
loglevels = { 'NOTSET':0 , 'DEBUG':10 ,'INFO': 20 , 'WARNING':30, 'ERROR':40, 'SEVERE':40, 'CRITICAL':50}
#initialise a logger
browserlog = logging.getLogger("chrome")
#get browser logs
slurped_logs = driver.get_log('browser')
for entry in slurped_logs:
#convert broswer log to python log format
rec = browserlog.makeRecord("%s.%s"%(browserlog.name,entry['source']),loglevels.get(entry['level']),'.',0,entry['message'],None,None)
rec.created = entry['timestamp'] /1000 # log using original timestamp.. us -> ms
try:
#add browser log to python log
browserlog.handle(rec)
except:
print(entry)
#and return logs incase you want them
return slurped_logs
def demo():
caps = webdriver.DesiredCapabilities.CHROME.copy()
caps['goog:loggingPrefs'] = { 'browser':'ALL' }
driver = webdriver.Chrome(desired_capabilities=caps )
driver.get("http://localhost")
consolemsgs = get_browser_log_entries(driver)
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s:%(levelname)7s:%(message)s')
logging.info("start")
demo()
logging.info("end")
Note that calling driver.get_log('browser') will cause the next call to return nothing until more logs are written to the console.
I would suggest saving the logs to a variable first. For example below logs_2 will equal [].
If you need something in the console to test you can use:
self.driver.execute_script("""
function myFunction() {
console.log("Window loaded")
}
if(window.attachEvent) {
window.attachEvent('onload', myFunction());
} else {
if(window.onload) {
var curronload = window.onload;
var newonload = function(evt) {
curronload(evt);
myFunction(evt);
};
window.onload = newonload;
} else {
window.onload = myFunction();
}
}
""")
logs_1 = driver.get_log('browser')
print("A::", logs_1 )
logs_2 = driver.get_log('browser')
print("B::", logs_2 )
for entry in logs_1:
print("Aa::",entry)
for entry in logs_2:
print("Bb::",entry)
See the answer from msridhar for what should go above my example code.