Compare commits
	
		
			9 commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 77b9b213d4 | |||
| a47f32b0fe | |||
|   | 06394dc3e3 | ||
|   | 70b103ebd8 | ||
|   | b96c828fa3 | ||
|   | 1fb3ee10d0 | ||
|   | 95f8ae318a | ||
|   | f0dc65ee08 | ||
|   | ab12cba1d5 | 
					 8 changed files with 91 additions and 143 deletions
				
			
		
							
								
								
									
										15
									
								
								CHANGELOG.md
									
										
									
									
									
								
							
							
						
						
									
										15
									
								
								CHANGELOG.md
									
										
									
									
									
								
							|  | @ -5,6 +5,21 @@ All notable changes to rattail-tutorial 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 (probably doesn't) adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). | and this project (probably doesn't) adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). | ||||||
| 
 | 
 | ||||||
|  | ## v0.3.2 (2025-09-20) | ||||||
|  | 
 | ||||||
|  | ### Fix | ||||||
|  | 
 | ||||||
|  | - fix config extension entry point | ||||||
|  | - avoid deprecated base class for config extension | ||||||
|  | - update config for custom emails | ||||||
|  | - refactor custom menu builder, to inherit some menus | ||||||
|  | 
 | ||||||
|  | ## v0.3.1 (2024-07-01) | ||||||
|  | 
 | ||||||
|  | ### Fix | ||||||
|  | 
 | ||||||
|  | - remove legacy command definitions | ||||||
|  | 
 | ||||||
| ## v0.3.0 (2024-07-01) | ## v0.3.0 (2024-07-01) | ||||||
| 
 | 
 | ||||||
| ### Feat | ### Feat | ||||||
|  |  | ||||||
|  | @ -1,13 +1,9 @@ | ||||||
| .. -*- mode: rst -*- |  | ||||||
| 
 | 
 | ||||||
| rattail-tutorial | # rattail-tutorial | ||||||
| ================ |  | ||||||
| 
 | 
 | ||||||
| This project is intended for use as a "tutorial" for Rattail app development. | This project is intended for use as a "tutorial" for Rattail app development. | ||||||
| 
 | 
 | ||||||
| It contains documentation for the tutorial itself, but also contains | It contains documentation for the tutorial itself, but also contains | ||||||
| code for the tutorial app, which users may run locally for testing. | code for the tutorial app, which users may run locally for testing. | ||||||
| 
 | 
 | ||||||
| See the `Rattail website`_ for more info. | See the [Rattail website](https://rattailproject.org/) for more info. | ||||||
| 
 |  | ||||||
| .. _`Rattail website`: https://rattailproject.org/ |  | ||||||
|  | @ -125,7 +125,7 @@ rattail-tutorial app instead, you should do this:: | ||||||
| 
 | 
 | ||||||
|    mkdir -p ~/src |    mkdir -p ~/src | ||||||
|    cd ~/src |    cd ~/src | ||||||
|    git clone https://rattailproject.org/git/rattail-tutorial.git |    git clone https://forgejo.wuttaproject.org/rattail/rattail-tutorial.git | ||||||
|    pip install -e rattail-tutorial |    pip install -e rattail-tutorial | ||||||
| 
 | 
 | ||||||
| Creating the Project | Creating the Project | ||||||
|  |  | ||||||
|  | @ -6,9 +6,9 @@ build-backend = "hatchling.build" | ||||||
| 
 | 
 | ||||||
| [project] | [project] | ||||||
| name = "rattail-tutorial" | name = "rattail-tutorial" | ||||||
| version = "0.3.0" | version = "0.3.2" | ||||||
| description = "Rattail Development Tutorial" | description = "Rattail Development Tutorial" | ||||||
| readme = "README.rst" | readme = "README.md" | ||||||
| authors = [{name = "Lance Edgar", email = "lance@edbob.org"}] | authors = [{name = "Lance Edgar", email = "lance@edbob.org"}] | ||||||
| license = {text = "GNU GPL v3+"} | license = {text = "GNU GPL v3+"} | ||||||
| classifiers = [ | classifiers = [ | ||||||
|  | @ -42,18 +42,18 @@ rattail_tutorial = "rattail_tutorial.commands:rattail_tutorial_typer" | ||||||
| main = "rattail_tutorial.web.app:main" | main = "rattail_tutorial.web.app:main" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| [project.entry-points."rattail.config.extensions"] | [project.entry-points."wutta.config.extensions"] | ||||||
| rattail_tutorial = "rattail_tutorial.config:Rattail_tutorialConfig" | rattail_tutorial = "rattail_tutorial.config:RattailTutorialConfig" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| [project.entry-points."rattail_tutorial.subcommands"] | [project.entry-points."rattail.emails"] | ||||||
| hello = "rattail_tutorial.commands:HelloWorld" | rattail_tutorial = "rattail_tutorial.emails" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| [project.urls] | [project.urls] | ||||||
| Homepage = "https://rattailproject.org" | Homepage = "https://rattailproject.org" | ||||||
| repository = "https://kallithea.rattailproject.org/rattail-project/rattail-tutorial" | repository = "https://forgejo.wuttaproject.org/rattail/rattail-tutorial" | ||||||
| Changelog = "https://kallithea.rattailproject.org/rattail-project/rattail-tutorial/files/master/CHANGELOG.md" | Changelog = "https://forgejo.wuttaproject.org/rattail/rattail-tutorial/src/branch/master/CHANGELOG.md" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| [tool.commitizen] | [tool.commitizen] | ||||||
|  |  | ||||||
|  | @ -28,9 +28,7 @@ import sys | ||||||
| 
 | 
 | ||||||
| import typer | import typer | ||||||
| 
 | 
 | ||||||
| from rattail import commands |  | ||||||
| from rattail.commands.typer import make_typer | from rattail.commands.typer import make_typer | ||||||
| from rattail_tutorial import __version__ |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| rattail_tutorial_typer = make_typer( | rattail_tutorial_typer = make_typer( | ||||||
|  | @ -47,33 +45,3 @@ def hello( | ||||||
|     The requisite 'hello world' example |     The requisite 'hello world' example | ||||||
|     """ |     """ | ||||||
|     sys.stdout.write("hello world!\n") |     sys.stdout.write("hello world!\n") | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| def main(*args): |  | ||||||
|     """ |  | ||||||
|     Main entry point for Rattail Tutorial command system |  | ||||||
|     """ |  | ||||||
|     args = list(args or sys.argv[1:]) |  | ||||||
|     cmd = Command() |  | ||||||
|     cmd.run(*args) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class Command(commands.Command): |  | ||||||
|     """ |  | ||||||
|     Main command for Rattail Tutorial |  | ||||||
|     """ |  | ||||||
|     name = 'rattail_tutorial' |  | ||||||
|     version = __version__ |  | ||||||
|     description = "Rattail Tutorial (custom Rattail system)" |  | ||||||
|     long_description = '' |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class HelloWorld(commands.Subcommand): |  | ||||||
|     """ |  | ||||||
|     The requisite 'hello world' example |  | ||||||
|     """ |  | ||||||
|     name = 'hello' |  | ||||||
|     description = __doc__.strip() |  | ||||||
| 
 |  | ||||||
|     def run(self, args): |  | ||||||
|         self.stdout.write("hello world!\n") |  | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ | ||||||
| ################################################################################ | ################################################################################ | ||||||
| # | # | ||||||
| #  Rattail -- Retail Software Framework | #  Rattail -- Retail Software Framework | ||||||
| #  Copyright © 2010-2019 Lance Edgar | #  Copyright © 2010-2024 Lance Edgar | ||||||
| # | # | ||||||
| #  This file is part of Rattail. | #  This file is part of Rattail. | ||||||
| # | # | ||||||
|  | @ -24,10 +24,10 @@ | ||||||
| Custom config | Custom config | ||||||
| """ | """ | ||||||
| 
 | 
 | ||||||
| from rattail.config import ConfigExtension | from wuttjamaican.conf import WuttaConfigExtension | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Rattail_tutorialConfig(ConfigExtension): | class RattailTutorialConfig(WuttaConfigExtension): | ||||||
|     """ |     """ | ||||||
|     Rattail config extension for Rattail Tutorial |     Rattail config extension for Rattail Tutorial | ||||||
|     """ |     """ | ||||||
|  | @ -36,5 +36,4 @@ class Rattail_tutorialConfig(ConfigExtension): | ||||||
|     def configure(self, config): |     def configure(self, config): | ||||||
| 
 | 
 | ||||||
|         # set some default config values |         # set some default config values | ||||||
|         config.setdefault('rattail.mail', 'emails', 'rattail_tutorial.emails') |         config.setdefault('tailbone.menus.handler', 'rattail_tutorial.web.menus:TutorialMenuHandler') | ||||||
|         config.setdefault('tailbone', 'menus', 'rattail_tutorial.web.menus') |  | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ | ||||||
| ################################################################################ | ################################################################################ | ||||||
| # | # | ||||||
| #  Rattail -- Retail Software Framework | #  Rattail -- Retail Software Framework | ||||||
| #  Copyright © 2010-2019 Lance Edgar | #  Copyright © 2010-2024 Lance Edgar | ||||||
| # | # | ||||||
| #  This file is part of Rattail. | #  This file is part of Rattail. | ||||||
| # | # | ||||||
|  | @ -26,9 +26,6 @@ Custom email profiles | ||||||
| 
 | 
 | ||||||
| from rattail.mail import Email | from rattail.mail import Email | ||||||
| 
 | 
 | ||||||
| # bring in some common ones from rattail |  | ||||||
| from rattail.emails import datasync_error_watcher_get_changes, filemon_action_error |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| class rattail_import_sample_updates(Email): | class rattail_import_sample_updates(Email): | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ | ||||||
| ################################################################################ | ################################################################################ | ||||||
| # | # | ||||||
| #  Rattail -- Retail Software Framework | #  Rattail -- Retail Software Framework | ||||||
| #  Copyright © 2010-2019 Lance Edgar | #  Copyright © 2010-2024 Lance Edgar | ||||||
| # | # | ||||||
| #  This file is part of Rattail. | #  This file is part of Rattail. | ||||||
| # | # | ||||||
|  | @ -24,166 +24,139 @@ | ||||||
| Web Menus | Web Menus | ||||||
| """ | """ | ||||||
| 
 | 
 | ||||||
|  | from tailbone import menus as base | ||||||
| 
 | 
 | ||||||
| def simple_menus(request): |  | ||||||
|     url = request.route_url |  | ||||||
| 
 | 
 | ||||||
|     menus = [ | class TutorialMenuHandler(base.MenuHandler): | ||||||
|         { |     """ | ||||||
|  |     Demo menu handler | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     def make_menus(self, request, **kwargs): | ||||||
|  | 
 | ||||||
|  |         products_menu = self.make_products_menu(request) | ||||||
|  | 
 | ||||||
|  |         vendors_menu = self.make_vendors_menu(request) | ||||||
|  | 
 | ||||||
|  |         company_menu = self.make_company_menu(request) | ||||||
|  | 
 | ||||||
|  |         batches_menu = self.make_batches_menu(request) | ||||||
|  | 
 | ||||||
|  |         admin_menu = self.make_admin_menu(request, | ||||||
|  |                                           include_stores=False, | ||||||
|  |                                           include_tenders=False) | ||||||
|  | 
 | ||||||
|  |         menus = [ | ||||||
|  |             products_menu, | ||||||
|  |             vendors_menu, | ||||||
|  |             company_menu, | ||||||
|  |             batches_menu, | ||||||
|  |             admin_menu, | ||||||
|  |         ] | ||||||
|  | 
 | ||||||
|  |         return menus | ||||||
|  | 
 | ||||||
|  |     def make_products_menu(self, request, **kwargs): | ||||||
|  |         return { | ||||||
|             'title': "Products", |             'title': "Products", | ||||||
|             'type': 'menu', |             'type': 'menu', | ||||||
|             'items': [ |             'items': [ | ||||||
|                 { |                 { | ||||||
|                     'title': "Products", |                     'title': "Products", | ||||||
|                     'url': url('products'), |                     'route': 'products', | ||||||
|                     'perm': 'products.list', |                     'perm': 'products.list', | ||||||
|                 }, |                 }, | ||||||
|                 { |                 { | ||||||
|                     'title': "Brands", |                     'title': "Brands", | ||||||
|                     'url': url('brands'), |                     'route': 'brands', | ||||||
|                     'perm': 'brands.list', |                     'perm': 'brands.list', | ||||||
|                 }, |                 }, | ||||||
|                 { |                 { | ||||||
|                     'title': "Report Codes", |                     'title': "Report Codes", | ||||||
|                     'url': url('reportcodes'), |                     'route': 'reportcodes', | ||||||
|                     'perm': 'reportcodes.list', |                     'perm': 'reportcodes.list', | ||||||
|                 }, |                 }, | ||||||
|             ], |             ], | ||||||
|         }, |         } | ||||||
|         { | 
 | ||||||
|  |     def make_vendors_menu(self, request, **kwargs): | ||||||
|  |         return { | ||||||
|             'title': "Vendors", |             'title': "Vendors", | ||||||
|             'type': 'menu', |             'type': 'menu', | ||||||
|             'items': [ |             'items': [ | ||||||
|                 { |                 { | ||||||
|                     'title': "Vendors", |                     'title': "Vendors", | ||||||
|                     'url': url('vendors'), |                     'route': 'vendors', | ||||||
|                     'perm': 'vendors.list', |                     'perm': 'vendors.list', | ||||||
|                 }, |                 }, | ||||||
|                 {'type': 'sep'}, |                 {'type': 'sep'}, | ||||||
|                 { |                 { | ||||||
|                     'title': "Catalogs", |                     'title': "Catalogs", | ||||||
|                     'url': url('vendorcatalogs'), |                     'route': 'vendorcatalogs', | ||||||
|                     'perm': 'vendorcatalogs.list', |                     'perm': 'vendorcatalogs.list', | ||||||
|                 }, |                 }, | ||||||
|                 { |                 { | ||||||
|                     'title': "Upload New Catalog", |                     'title': "Upload New Catalog", | ||||||
|                     'url': url('vendorcatalogs.create'), |                     'route': 'vendorcatalogs.create', | ||||||
|                     'perm': 'vendorcatalogs.create', |                     'perm': 'vendorcatalogs.create', | ||||||
|                 }, |                 }, | ||||||
|             ], |             ], | ||||||
|         }, |         } | ||||||
|         { | 
 | ||||||
|  |     def make_company_menu(self, request, **kwargs): | ||||||
|  |         return { | ||||||
|             'title': "Company", |             'title': "Company", | ||||||
|             'type': 'menu', |             'type': 'menu', | ||||||
|             'items': [ |             'items': [ | ||||||
|                 { |                 { | ||||||
|                     'title': "Stores", |                     'title': "Stores", | ||||||
|                     'url': url('stores'), |                     'route': 'stores', | ||||||
|                     'perm': 'stores.list', |                     'perm': 'stores.list', | ||||||
|                 }, |                 }, | ||||||
|                 { |                 { | ||||||
|                     'title': "Departments", |                     'title': "Departments", | ||||||
|                     'url': url('departments'), |                     'route': 'departments', | ||||||
|                     'perm': 'departments.list', |                     'perm': 'departments.list', | ||||||
|                 }, |                 }, | ||||||
|                 { |                 { | ||||||
|                     'title': "Subdepartments", |                     'title': "Subdepartments", | ||||||
|                     'url': url('subdepartments'), |                     'route': 'subdepartments', | ||||||
|                     'perm': 'subdepartments.list', |                     'perm': 'subdepartments.list', | ||||||
|                 }, |                 }, | ||||||
|                 {'type': 'sep'}, |                 {'type': 'sep'}, | ||||||
|                 { |                 { | ||||||
|                     'title': "Employees", |                     'title': "Employees", | ||||||
|                     'url': url('employees'), |                     'route': 'employees', | ||||||
|                     'perm': 'employees.list', |                     'perm': 'employees.list', | ||||||
|                 }, |                 }, | ||||||
|                 {'type': 'sep'}, |                 {'type': 'sep'}, | ||||||
|                 { |                 { | ||||||
|                     'title': "Customers", |                     'title': "Customers", | ||||||
|                     'url': url('customers'), |                     'route': 'customers', | ||||||
|                     'perm': 'customers.list', |                     'perm': 'customers.list', | ||||||
|                 }, |                 }, | ||||||
|                 { |                 { | ||||||
|                     'title': "Customer Groups", |                     'title': "Customer Groups", | ||||||
|                     'url': url('customergroups'), |                     'route': 'customergroups', | ||||||
|                     'perm': 'customergroups.list', |                     'perm': 'customergroups.list', | ||||||
|                 }, |                 }, | ||||||
|             ], |             ], | ||||||
|         }, |         } | ||||||
|         { | 
 | ||||||
|  |     def make_batches_menu(self, request, **kwargs): | ||||||
|  |         return { | ||||||
|             'title': "Batches", |             'title': "Batches", | ||||||
|             'type': 'menu', |             'type': 'menu', | ||||||
|             'items': [ |             'items': [ | ||||||
|                 { |                 { | ||||||
|                     'title': "Handheld", |                     'title': "Handheld", | ||||||
|                     'url': url('batch.handheld'), |                     'route': 'batch.handheld', | ||||||
|                     'perm': 'batch.handheld.list', |                     'perm': 'batch.handheld.list', | ||||||
|                 }, |                 }, | ||||||
|                 { |                 { | ||||||
|                     'title': "Inventory", |                     'title': "Inventory", | ||||||
|                     'url': url('batch.inventory'), |                     'route': 'batch.inventory', | ||||||
|                     'perm': 'batch.inventory.list', |                     'perm': 'batch.inventory.list', | ||||||
|                 }, |                 }, | ||||||
|             ], |             ], | ||||||
|         }, |         } | ||||||
|         { |  | ||||||
|             'title': "Admin", |  | ||||||
|             'type': 'menu', |  | ||||||
|             'items': [ |  | ||||||
|                 { |  | ||||||
|                     'title': "Users", |  | ||||||
|                     'url': url('users'), |  | ||||||
|                     'perm': 'users.list', |  | ||||||
|                 }, |  | ||||||
|                 { |  | ||||||
|                     'title': "User Events", |  | ||||||
|                     'url': url('userevents'), |  | ||||||
|                     'perm': 'userevents.list', |  | ||||||
|                 }, |  | ||||||
|                 { |  | ||||||
|                     'title': "Roles", |  | ||||||
|                     'url': url('roles'), |  | ||||||
|                     'perm': 'roles.list', |  | ||||||
|                 }, |  | ||||||
|                 {'type': 'sep'}, |  | ||||||
|                 { |  | ||||||
|                     'title': "App Settings", |  | ||||||
|                     'url': url('appsettings'), |  | ||||||
|                     'perm': 'settings.list', |  | ||||||
|                 }, |  | ||||||
|                 { |  | ||||||
|                     'title': "Email Settings", |  | ||||||
|                     'url': url('emailprofiles'), |  | ||||||
|                     'perm': 'emailprofiles.list', |  | ||||||
|                 }, |  | ||||||
|                 { |  | ||||||
|                     'title': "Email Attempts", |  | ||||||
|                     'url': url('email_attempts'), |  | ||||||
|                     'perm': 'email_attempts.list', |  | ||||||
|                 }, |  | ||||||
|                 { |  | ||||||
|                     'title': "Raw Settings", |  | ||||||
|                     'url': url('settings'), |  | ||||||
|                     'perm': 'settings.list', |  | ||||||
|                 }, |  | ||||||
|                 {'type': 'sep'}, |  | ||||||
|                 { |  | ||||||
|                     'title': "DataSync Changes", |  | ||||||
|                     'url': url('datasyncchanges'), |  | ||||||
|                     'perm': 'datasync.list', |  | ||||||
|                 }, |  | ||||||
|                 { |  | ||||||
|                     'title': "Tables", |  | ||||||
|                     'url': url('tables'), |  | ||||||
|                     'perm': 'tables.list', |  | ||||||
|                 }, |  | ||||||
|                 { |  | ||||||
|                     'title': "Rattail Tutorial Upgrades", |  | ||||||
|                     'url': url('upgrades'), |  | ||||||
|                     'perm': 'upgrades.list', |  | ||||||
|                 }, |  | ||||||
|             ], |  | ||||||
|         }, |  | ||||||
|     ] |  | ||||||
| 
 |  | ||||||
|     return menus |  | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue