Compare commits
2 commits
d6c1e688b1
...
960dbfdee6
| Author | SHA1 | Date | |
|---|---|---|---|
| 960dbfdee6 | |||
| 7225d6b453 |
7 changed files with 213 additions and 20 deletions
|
|
@ -5,6 +5,12 @@ All notable changes to WuttaPOS will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## v0.4.1 (2026-01-03)
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- add basic support for install/setup of terminal
|
||||||
|
|
||||||
## v0.4.0 (2026-01-03)
|
## v0.4.0 (2026-01-03)
|
||||||
|
|
||||||
First release under the new project.
|
First release under the new project.
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ For now this only describes a *development* setup, which assumes the following:
|
||||||
* Python 3.11 or newer
|
* Python 3.11 or newer
|
||||||
* database in PostgreSQL or MySQL
|
* database in PostgreSQL or MySQL
|
||||||
|
|
||||||
These steps will setup both the server and terminal in a shared
|
These steps will setup both the Server and Terminal in a shared
|
||||||
virtual environment.
|
virtual environment.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -40,13 +40,13 @@ Install Server
|
||||||
|
|
||||||
**Please note, you must create your database before running the installer.**
|
**Please note, you must create your database before running the installer.**
|
||||||
|
|
||||||
Run the WuttaPOS installer to setup the server app:
|
Run the WuttaPOS installer to setup the Server app:
|
||||||
|
|
||||||
.. code-block:: ini
|
.. code-block:: ini
|
||||||
|
|
||||||
bin/wuttapos install
|
bin/wuttapos install
|
||||||
|
|
||||||
Now you can run the server app via command line:
|
Now you can run the Server app via command line:
|
||||||
|
|
||||||
.. code-block:: ini
|
.. code-block:: ini
|
||||||
|
|
||||||
|
|
@ -86,4 +86,48 @@ should be improved - but that will come later.
|
||||||
Install Terminal
|
Install Terminal
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
TODO: this is not yet documented
|
**Please note, this assumes you already installed the Server as described above.**
|
||||||
|
|
||||||
|
For now, we'll just install the Terminal alongside the Server. They
|
||||||
|
will share the same virtual environment, installed code, app database,
|
||||||
|
and "most of" the config files.
|
||||||
|
|
||||||
|
So within your virtual environment, run the same installer again:
|
||||||
|
|
||||||
|
.. code-block:: ini
|
||||||
|
|
||||||
|
bin/wuttapos install
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
You will be asked for store and terminal IDs - these should be
|
||||||
|
valid and refer to actual records for those types, within the
|
||||||
|
database. See the Admin menu of the Server web app to manage those
|
||||||
|
records.
|
||||||
|
|
||||||
|
At this point the Terminal app should be ready to go. To run the
|
||||||
|
standalone GUI:
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
bin/wuttapos -c app/terminal.conf run
|
||||||
|
|
||||||
|
You will need to login; the POS uses a special set of permissions but
|
||||||
|
the first admin user should already have all that are needed. So just
|
||||||
|
login using same credentials as for the Server app.
|
||||||
|
|
||||||
|
It's also possible (due to the magic of Flet/Flutter) to *serve* the
|
||||||
|
Terminal as a web app:
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
bin/wuttapos -c app/terminal.conf serve
|
||||||
|
|
||||||
|
In that case (by default) you can browse it at http://localhost:8332
|
||||||
|
|
||||||
|
That might be useful for online demo purposes etc. but definitely the
|
||||||
|
intention is to run as standalone GUI for production. (However the
|
||||||
|
story around tablets is TBD.)
|
||||||
|
|
||||||
|
For now, running as a web service like that is not a supported
|
||||||
|
feature.
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ build-backend = "hatchling.build"
|
||||||
name = "WuttaPOS"
|
name = "WuttaPOS"
|
||||||
# nb. 0.3.0 was the last release of the previous rattail WuttaPOS app.
|
# nb. 0.3.0 was the last release of the previous rattail WuttaPOS app.
|
||||||
# pretty sure this will bump to 0.4.0 and then i can remove this note.
|
# pretty sure this will bump to 0.4.0 and then i can remove this note.
|
||||||
version = "0.4.0"
|
version = "0.4.1"
|
||||||
description = "Point of Sale system based on Wutta Framework"
|
description = "Point of Sale system based on Wutta Framework"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}]
|
authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}]
|
||||||
|
|
@ -32,7 +32,7 @@ classifiers = [
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"psycopg2",
|
"psycopg2",
|
||||||
"WuttJamaican[db]>=0.28.2",
|
"WuttJamaican[db]>=0.28.4",
|
||||||
"WuttaSync",
|
"WuttaSync",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@
|
||||||
See also: :ref:`wuttapos-run`
|
See also: :ref:`wuttapos-run`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
import typer
|
import typer
|
||||||
|
|
||||||
from wuttapos.cli import wuttapos_typer
|
from wuttapos.cli import wuttapos_typer
|
||||||
|
|
@ -37,4 +39,11 @@ def run(ctx: typer.Context):
|
||||||
from wuttapos.terminal.app import run_app
|
from wuttapos.terminal.app import run_app
|
||||||
|
|
||||||
config = ctx.parent.wutta_config
|
config = ctx.parent.wutta_config
|
||||||
run_app(config)
|
|
||||||
|
# nb. it does not seem possible (?) to inject our config when
|
||||||
|
# launching the Flet app, which means it will create a *separate*
|
||||||
|
# config for itself..this should ensure it has the right settings.
|
||||||
|
# see also notes in wuttapos.terminal.app module, for run_app()
|
||||||
|
os.environ["WUTTA_CONFIG_FILES"] = os.pathsep.join(config.get_prioritized_files())
|
||||||
|
|
||||||
|
run_app()
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
Install handler for WuttaPOS
|
Install handler for WuttaPOS
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
@ -37,14 +38,62 @@ class InstallHandler(base.InstallHandler):
|
||||||
|
|
||||||
template_paths = ["wuttapos:installer-templates"]
|
template_paths = ["wuttapos:installer-templates"]
|
||||||
|
|
||||||
|
store_id = None
|
||||||
|
terminal_id = None
|
||||||
|
alongside = False
|
||||||
|
|
||||||
def do_install_steps(self):
|
def do_install_steps(self):
|
||||||
|
|
||||||
# prompt for install type first
|
# prompt for install type first
|
||||||
self.get_install_type()
|
self.get_install_type()
|
||||||
|
|
||||||
|
# install server/terminal dependencies
|
||||||
|
self.install_app_deps()
|
||||||
|
|
||||||
# then everything else
|
# then everything else
|
||||||
super().do_install_steps()
|
super().do_install_steps()
|
||||||
|
|
||||||
|
def sanity_check(self):
|
||||||
|
"""
|
||||||
|
We override this because the normal up-front sanity check
|
||||||
|
includes a check for the app dir. But we need to delay that
|
||||||
|
one a bit, so behavior depends on which "install type" we're
|
||||||
|
doing.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def check_appdir(self):
|
||||||
|
"""
|
||||||
|
We bypass the normal check here, if the current install is for
|
||||||
|
terminal alongside server.
|
||||||
|
"""
|
||||||
|
if self.install_type == "terminal":
|
||||||
|
|
||||||
|
# does appdir exist yet?
|
||||||
|
appdir = os.path.join(sys.prefix, "app")
|
||||||
|
if os.path.exists(appdir):
|
||||||
|
|
||||||
|
# install alongside server?
|
||||||
|
self.alongside = self.prompt_bool(
|
||||||
|
"install alongside server?", default=False
|
||||||
|
)
|
||||||
|
if self.alongside:
|
||||||
|
# this mode expects the appdir to exist, so continue
|
||||||
|
return
|
||||||
|
|
||||||
|
else:
|
||||||
|
# no appdir - means we should install "everything" for
|
||||||
|
# the terminal, but we don't support that yet
|
||||||
|
self.rprint(
|
||||||
|
f"\n\t[bold red]sorry, full terminal install not yet supported[/bold red]\n"
|
||||||
|
)
|
||||||
|
self.rprint(
|
||||||
|
f"\n\tPlease install the server, then terminal alongside that.\n"
|
||||||
|
)
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
# do normal check
|
||||||
|
super().check_appdir()
|
||||||
|
|
||||||
def get_install_type(self):
|
def get_install_type(self):
|
||||||
|
|
||||||
# prompt user
|
# prompt user
|
||||||
|
|
@ -55,22 +104,88 @@ class InstallHandler(base.InstallHandler):
|
||||||
# remember the answer
|
# remember the answer
|
||||||
self.install_type = install_type
|
self.install_type = install_type
|
||||||
|
|
||||||
if self.install_type != "server":
|
# now we can check the app dir; do this before further questions
|
||||||
self.rprint(
|
self.check_appdir()
|
||||||
"[bold red]sorry, terminal install is not yet implemented[/bold red]\n"
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# install dependencies
|
# stop here for server, but we have more questions for terminal
|
||||||
if self.install_type == "server":
|
if self.install_type == "server":
|
||||||
self.install_server_deps()
|
return
|
||||||
|
|
||||||
def install_server_deps(self):
|
self.rprint(
|
||||||
subprocess.check_call(
|
"\n\n\t[blue]Next you must specify the Store and Terminal IDs.[/blue]"
|
||||||
[sys.executable, "-m", "pip", "install", "WuttaPOS[server]"]
|
|
||||||
)
|
)
|
||||||
|
self.rprint(
|
||||||
|
"\n\tThese should match records in your DB; see the Server app for info.\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
# store_id
|
||||||
|
while not self.store_id:
|
||||||
|
self.store_id = self.prompt_generic("Store ID")
|
||||||
|
|
||||||
|
# terminal_id
|
||||||
|
while not self.terminal_id:
|
||||||
|
self.terminal_id = self.prompt_generic("Terminal ID")
|
||||||
|
|
||||||
|
def install_app_deps(self):
|
||||||
|
|
||||||
|
if self.install_type == "server":
|
||||||
|
subprocess.check_call(
|
||||||
|
[sys.executable, "-m", "pip", "install", "WuttaPOS[server]"]
|
||||||
|
)
|
||||||
|
|
||||||
|
elif self.install_type == "terminal":
|
||||||
|
subprocess.check_call(
|
||||||
|
[sys.executable, "-m", "pip", "install", "WuttaPOS[terminal]"]
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_dbinfo(self):
|
||||||
|
if self.alongside:
|
||||||
|
return {"dburl": self.config.appdb_engine.url}
|
||||||
|
|
||||||
|
return super().get_dbinfo()
|
||||||
|
|
||||||
def make_template_context(self, dbinfo, **kwargs):
|
def make_template_context(self, dbinfo, **kwargs):
|
||||||
context = super().make_template_context(dbinfo, **kwargs)
|
context = super().make_template_context(dbinfo, **kwargs)
|
||||||
|
|
||||||
context["install_type"] = self.install_type
|
context["install_type"] = self.install_type
|
||||||
|
context["store_id"] = self.store_id
|
||||||
|
context["terminal_id"] = self.terminal_id
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
def write_all_config_files(self, appdir, context):
|
||||||
|
if self.alongside:
|
||||||
|
# just want to add terminal.conf for this mode
|
||||||
|
self.write_terminal_conf(appdir, context)
|
||||||
|
return
|
||||||
|
|
||||||
|
# new app, so write normal files
|
||||||
|
super().write_all_config_files(appdir, context)
|
||||||
|
|
||||||
|
def write_terminal_conf(self, appdir, context):
|
||||||
|
term_context = dict(context)
|
||||||
|
self.make_config_file(
|
||||||
|
"terminal.conf.mako", os.path.join(appdir, "terminal.conf"), **term_context
|
||||||
|
)
|
||||||
|
|
||||||
|
def install_db_schema(self, db_url, appdir=None):
|
||||||
|
if self.alongside:
|
||||||
|
# no need to install schema here
|
||||||
|
return False
|
||||||
|
|
||||||
|
return super().install_db_schema(db_url, appdir=appdir)
|
||||||
|
|
||||||
|
def show_goodbye(self):
|
||||||
|
"""
|
||||||
|
Show the final message; this assumes setup completed okay.
|
||||||
|
|
||||||
|
This is normally called by :meth:`run()`.
|
||||||
|
"""
|
||||||
|
if self.alongside:
|
||||||
|
self.rprint("\n\t[bold green]initial setup is complete![/bold green]")
|
||||||
|
self.rprint("\n\tyou can run the terminal GUI app with:")
|
||||||
|
self.rprint(f"\n\t[blue]cd {sys.prefix}[/blue]")
|
||||||
|
self.rprint("\t[blue]bin/wuttapos -c app/terminal.conf run[/blue]\n")
|
||||||
|
return
|
||||||
|
|
||||||
|
super().show_goodbye()
|
||||||
|
|
|
||||||
17
src/wuttapos/installer-templates/terminal.conf.mako
Normal file
17
src/wuttapos/installer-templates/terminal.conf.mako
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
## -*- mode: conf; -*-
|
||||||
|
|
||||||
|
<%text>############################################################</%text>
|
||||||
|
#
|
||||||
|
# ${app_title} - terminal installed alongside the server
|
||||||
|
#
|
||||||
|
<%text>############################################################</%text>
|
||||||
|
|
||||||
|
[wutta.config]
|
||||||
|
require = %(here)s/wutta.conf
|
||||||
|
|
||||||
|
[wuttapos]
|
||||||
|
store_id = ${store_id}
|
||||||
|
terminal_id = ${terminal_id}
|
||||||
|
|
||||||
|
[wutta_continuum]
|
||||||
|
enable_versioning = false
|
||||||
|
|
@ -282,9 +282,11 @@ def main(page: ft.Page):
|
||||||
page.go("/login")
|
page.go("/login")
|
||||||
|
|
||||||
|
|
||||||
# TODO: can we inject config to the main() via ft.app() kwargs somehow?
|
# TODO: is there any way to inject a config object into the new Flet
|
||||||
# pretty sure the `wuttapos open` command is trying to anyway..
|
# app? if so this would be the place to do it. currently in main()
|
||||||
def run_app(config=None):
|
# it always makes a new config for itself, as workaround. but also
|
||||||
|
# see notes in the wuttapos.cli.run module
|
||||||
|
def run_app():
|
||||||
ft.app(target=main, assets_dir=resource_path("wuttapos.terminal:assets"))
|
ft.app(target=main, assets_dir=resource_path("wuttapos.terminal:assets"))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue