Modifying packing slip to show a userProp?

I’m trying to customize and improve our workflow (mainly to make it more maintainable) by reworking listing templates and designs, and use inventory management better.

One small thing I’m trying to do this evening is modify the packing list template to show the “pick location” user property I have assigned the items. That way, when I print the packing list, I can carry it around and gather the items in an order without having to consult the little tiny User Properties field I’ve added in GS for every listing.

But I’m having trouble. Is the [[item.userProps.foo]] notation available in the packing slip template? Should it be [[transaction.userProps.foo]] instead? Does one need to dereference the item of the transaction?

later: oh no; transaction is a totally different table from item, isn’t it? and there’s no way to join in anything from item records? :cry:

I’m guessing here: is a transaction derived only from data downloaded from eBay? I notice everything I can explicitly see in that object would sensibly be available from the eBay listing itself.

I wonder if there is a way (probably not for me, but maybe for the GS devs) to infer the correct unique ID of the listing/item which generated the transaction, and reach back to the other table within the GS schema to get more? :pray:

To clarify for folks who might have a similar problem:

I store “location” information in the User Properties of inventory items and/or listings. I currently manage 3000+ running listings, and want to grow to 10k or so, but they are all unique items, so it’s not possible to keep all of them organized in physical space. So I hav been trying to make notes and be more organized so I can more easily know where to look for the physical objects.

Also, there is no room in the titles of most items for location numbers. From an object model standpoint, the User Properties fields seem like the correct place to do this job.

My current workflow is to select all the transaction items that are ready to ship, and print packing slips. Then I carry those printed slips around and gather the items to pack. At the moment, because there is no information on the generic GS packing slips about location, but I have been muddling through by manually looking up all the items in GS and jotting the location info onto the physical pages.

In order to grow, all I really need is a short printed list (or even a text file or string) with the listing title and the location field associated with each other.

GarageSale provides a lot of useful hooks! I got closer yesterday when I was revisiting this, than I ever have before.

This is a non-working AppleScript, which comes closer than ever IMHO to kludging what I need. My idea here is, if I cannot produce what I need in one step, I can at least write a string out that lists the items, and then maybe write a separate Javascript that accepts this string as an argument and prints the table of userProp values for those items!


tell application "GarageSale"
	-- start with an empty AppleScript list
	set pickListings to {}

	-- I have selected a bunch of orders in the GS app
	repeat with thisTransaction in (get selected ebay orders)
		-- a GS "eBay order" has one or more "eBay order transactions"
		set theseSales to (the ebay order transactions of thisTransaction)
		repeat with theSale in theseSales
			-- this is an awful kludge: I am getting the item's eBay ID, and then looking
			--  every (EVERY) GS listing for the one with that auction ID; this is awful!
			-- ... but it works

			set listingID to the transaction item title of theSale
			set theListing to (the first ebay listing whose item id is listingID)
			copy (the item id of theListing) to the end of pickListings
		end repeat
	end repeat

	-- the following is just to show me that I have successfully collected the IDs
	-- I could also have collected the GS database IDs 
	-- the temporary fix would be to create a Javascript now that I can paste this info into
	--   and have it produce the text I need
	--   because I have no way AFAIK to read the user properties with AppleScript

	display dialog pickListings as string
end tell

I have not yet checked whether there is Javascript support for the Orders table in GS, but it’s not mentioned in the manual. If there is, then I would be able to do all this stuff more easily in Javascript, and might even be able to jump the gap between the listing IDs in the order to the user properties of those listings.

It feels like such a small gap, and the GS folks have done so much to get close to spanning it… but it still seems to be broken!

But although there is some template language that will let me put items from the Orders table into the packing list HTML, all of that looks only at the transaction record, which is the “sale”. What I need is information that lives in the listing records referred to by the transaction. Or maybe even in the item record that produced the listing that was sold in that transaction. :face_palm:

For completeness, and maybe to provoke a useful disgust among the GS developers, I have kludged a way of doing this. It is horrible.

First in the Orders view of GS, I manually select the orders that are ready to ship. I don’t automate this because I may not want to ship everything today.

Then I invoke this AppleScript, which compiles a text string containing a syntactically valid Javascript list of the item ID strings for every listing in the orders.


tell application "GarageSale"
	set pickListings to "["
	repeat with thisTransaction in (get selected ebay orders)
		set theseSales to (the ebay order transactions of thisTransaction)
		repeat with theSale in theseSales
			set listingID to the transaction item title of theSale
			set theListing to (the first ebay listing whose item id is listingID)
			set pickListings to pickListings & "\"" & (the item id of theListing) & "\", "
		end repeat
	end repeat
	display dialog pickListings & "]"
end tell

For example, when I select a few orders now and run it, I get a dialog popup that looks like this:

Screenshot 2022-12-30 at 9.44.57 AM

Then I select that string (the dialog box size is limited by the height of my screen, I suppose, but if I ever sell more than 100 things in a day I will have other problems).

Then I open the Scripts window of GS, and open this Javascript and paste the string in to replace the const defined at the top. This hurts my soul. But I do it anyway, because there is apparently no other way to associate user properties and order items.

Here is the script with that list of numbers pasted into the const:

function run(){
	
	const pickList =

["354480712518", "354461422597", "354477165055", "354480720056", "304752135244", "304741347461", "304749482646", "354461422395", "304748753422", "354472577601", "304744673209", ]

;
	
	function idMatch(listing){
		return pickList.includes(listing.itemID);
	}
	
	consoleLog("Pick list for " + Date(Date.now()).toLocaleString() + "\n");
	
	let foo = allListings.filter(idMatch);
	
	for (var i in foo) {
    	consoleLog(
    		foo[i].title + 
    		"\nLocation:\t" +
    		foo[i].userProperties["CB_LOCATION"] +
    		"\n");
	}	
	
	consoleLog("ready to pick " + foo.length + " items");
}

When I run this, it takes a while, but eventually this string is produced in the consoleLog:

Pick list for Fri Dec 30 2022 09:49:56 GMT-0500 (Eastern Standard Time)
1966 Peg Bracken I TRY TO BEHAVE MYSELF humor ETIQUETTE Fawcett pb illustrated
Location:	mass market alphabetical

1938 Playbill YOU NEVER KNOW Hartman Theatre CLIFTON WEBB Toby Wing LUPE VELEZ a
Location:	playbills

2002 Humanoids METAL HURLANT #2 Beltran Jodorowsky Wazem EURO-COMIX first print
Location:	comics alphabetical

1996 Oct FANTASY & SCIENCE FICTION Harlan Ellison TANITH LEE Gene Wolfe BENFORD
Location:	wood shelf

1926 COLOR FOR YOU American Crayon Company ART INSTRUCTION color theory DESIGN
Location:	inflow

2002 Humanoids Publishing METAL HURLANT #3 Jodorowsky Beltran Alixe euro-comix
Location:	comics alphabetical

2007 Taleb THE BLACK SWAN Impact of the Highly Improbable FIRST PRINTING hc/dj
Location:	hardcovers alphabetical

1982 WRIGHT MORRIS: Photographs & Words FRIENDS OF PHOTOGRAPHY monograph ART pb
Location:	box 20220721.1

1991 J.P. Shanley THE BIG FUNK script Samuel French "A Casual Play"
Location:	play scripts

1973 Peg Bracken BUT I WOULDN'T HAVE MISSED IT FOR THE WORLD! humor travel
Location:	mass market alphabetical

1930 Playbill MAE WEST'S "SEX" English Theatre (Indianapolis) 
Location:	playbills

ready to pick 11 items

Then I can copy and paste that text and print it. Actually it seems as though I can just print the Javascript console by hitting Cmd-P when it’s active, so that’s convenient.

:sigh:

OK so I see several ways for GS to help, here:

  1. Allow packing slip design templates to refer to the listings associated with them. Something like [[transaction.item.userProps["foo"]]] would work, but there has to be some kind of hasMany relationship between transaction and actual item records, right?? This would solve this one problem I have been wrestling with for a long time.
  2. Allow AppleScript to access the user properties of listings (I could have done all this in a single AppleScript if I could read the userProps fields). Basically “everything the JS does” could happen in AS if I could access those fields. This would be OK but meh to AppleScript.
  3. Allow Javascript to access the Orders table so I can select some orders and then use JS to do all this. Basically “everything the AppleScript does” is unavailable to the JS, as far as I can tell. This would be great!

BUT the good thing is: I only do this once every day. So this works (painfully) for now.

Have you tried using this code in your custom packing slip ?

[[foreach order orders ordersLoop]]
    [[order.listing.userProps.foo]]
[[endforeach ordersLoop]]

… Yes?

I mean, it doesn’t error out, but I was basing my work on the manual, and based on that and the fact that nothing prints in this case, it looks like the order object is not reachable in the transaction report? I can access transaction and listing from this report, but listing cannot access the userProps AFAIK.

N.B. I am not running a beta at the moment.

I tried [[order.listing.userProps.foo]] inside the existing ordersLoop in a custom packageSlip and for me it worked like a charm.

OK I’ll give it a close look, and report later today. But I think now might be time to update the list of things you can do with the design language in the manual now, if it does work on your machine :slight_smile:

Have you checked that the order object is still connected to a listing, by invoking the “Show Listing” command ?

Screen Shot 2023-01-06 at 12.07.08

Wow, I’ve never once considered right-clicking on the image of the thing in the Orders window. :slight_smile:

But yes, it is still connected.

However I’m still failing badly to understand how the loop you suggested works in the Table packing list I’m trying to modify. Here’s my situation at the moment.

  1. Every Listing has a User Property called “CB_LOCATION”, which is what I want to add to the Table packing list.
  2. I’ve duplicated and edited the Table html template, and verified that my edited version is in fact being run by adding static text.
  3. I cannot get the code you provided to return any value, even if I remove all the surrounding table info

Indeed, the code you provide above is confusing. My orders have multiple transactions. That’s even how the Packing Slip HTML template you provide is organized! So help me understand how can one order be linked to only one listing? There are one or more listings associated with any order. Each listing is 1:1 for a transaction. Is this maybe a translation problem?

That’s the code I see in your own packing slip.

Anyway, here is the table I have been trying to make! Maybe seeing it will help?

<!DOCTYPE html>
<html>
	<head>
		<title>Corners Bumped Books Packing Slip</title>
		<style type="text/css">
				<!-- no change made; I've just hidden it for clarity -->
		</style>
	</head>
	<body>
		
		[[foreach order orders ordersLoop]]
		<div class="packingSlip">
			<header></header>
			<h1>[[localizer.Packing_Slip]]</h1>
			<hr>
			<div class="shippingAddress">
				[[order.htmlShippingAddress]]
			</div>
			<hr>
			<div class="orderDate">[[localizer.Order_Date]]: [[order.orderDate]]</div>
			<hr>
			<table class="orderedItems">
				<tr>
					<th>[[localizer.Pos]].</th>
					<th></th>
					<th>[[localizer.Name]]</th>
					<th>[[localizer.SKU]]</th>
					<th>inventory location</th>
					<th>[[localizer.Item_ID]]</th>
				</tr>

				[[foreach transaction order.transactions transactionsLoop]]
				<tr>
					<td>[[transaction.positionInOrder]]</td>
					<td class="itemImage">[[if transaction.thumbImagePath]]<img src="file://[[transaction.thumbImagePath]]">[[endif]]</td>
					<td>[[transaction.auctionTitle]]</td>
					<td>[[transaction.sku]]</td>
					<td>Location (of this listing)</td>
					<td>[[transaction.itemID]]</td>
				</tr>
				[[endforeach transactionsLoop]]
			</table>

			<hr>
			<footer>
				<i><img src="GarageSale.png"></i>[[localizer.Created_with_GarageSale_on_a_Mac]]<br>www.iwascoding.com/GarageSale
			</footer>
		</div>
		[[endforeach ordersLoop]]
	</body>
</html>

Tell me what template code I am allowed to use where I have the placeholder

<td>Location (of this listing)</td>

The information I want printed is in the listing record associated with this particular transaction. For each transaction in the order (which is the syntax of this table already) I want to print the transaction.listing.userProps.CB_LOCATION.

Except that is obviously not working syntax. So what is?

Your suggested code seems to be implying order.listing.userProps should work, but… how? I literally can’t see how it is possible with that syntax. One order can have many listings. The 1:1 mapping is listing <=> transaction, not order.

Clarification I am now running the beta (11) just to make sure nothing has snuck in. No luck.

Also, again in case it helps somebody who is trying to modify a packing slip and frustrated, I have to re-start GarageSale every time I modify the template file.

After the other thing is fixed… is there any way we could avoid that?

I was curious and tried it here with an order that contains two listings. I was a bit surprised but for me adding [[transaction.listing.userProps.foo]] seems to have worked even if placed inside the transaction loop, like this:

[[foreach transaction order.transactions transactionsLoop]]
	<tr>
		<td>[[transaction.positionInOrder]]</td>
		<td>[[transaction.itemID]]</td>
		<td>[[transaction.quantityPurchased]]</td>
		<td>[[transaction.listing.userProps.foo]]</td>
	</tr>
[[endforeach transactionsLoop]]

The user property I tried it with doesn’t contain an underscore character. Once I added one it no longer appeared in the packing slip. Maybe I have done something wrong here but trying it with CBLOCATION instead of CB_LOCATION might be worth a try!

1 Like

o.O

Yes that worked.

:man_facepalming: :infinity:

What a world. I named all the keys carefully after the last time I tried to get this all to work, so they were valid Ruby variable names. But of course GS isn’t written in Ruby, so that did nothing.

This is how progress feels, though!


later OK! And thank you, @kristian for patience.

So now the bug is: “the documentation needs to make clear that the keys of userProps must be syntactically allowed variable names in Mysterious Programming Language X if you are ever going to use them in code.” :slight_smile:

And also “The documentation should include all the permitted ways to reach between data models inventory item, listing, order and transaction.”

Those would really have helped.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.