Pārlūkot izejas kodu

Add very rough invoice type posts. Needs styling, particularly for print.

George Baugh 4 mēneši atpakaļ
vecāks
revīzija
0a22e40aaa

+ 14 - 1
lib/Trog/DataModule.pm

@@ -196,6 +196,8 @@ sub filter ( $self, $query, @filtered ) {
         } @$tags
     } @filtered unless grep { $_ eq 'admin' } @{ $query->{acls} };
 
+    @filtered = grep { ($_->{form} || '') eq $query->{form} } @filtered if $query->{form};
+
     @filtered = grep { $_->{title} =~ m/\Q$query->{like}\E/i || $_->{data} =~ m/\Q$query->{like}\E/i } @filtered if $query->{like};
 
     @filtered = grep { $_->{user} eq $query->{author} } @filtered if $query->{author};
@@ -336,7 +338,7 @@ our %schema = (
     'wallpaper_file' => $hashref_or_string,
     'wallpaper'      => $not_ref,
 
-    # user avatar, but does double duty in content posts as preview images on videos, etc
+    ## user avatar, but does double duty in content posts as preview images on videos, etc
     'preview_file' => $hashref_or_string,
     'preview'      => $not_ref,
 
@@ -345,6 +347,17 @@ our %schema = (
     'video_href'  => $not_ref,
     'file'        => $hashref_or_string,
     'attachments' => \&Ref::Util::is_arrayref,
+    'header'      => $not_ref,
+    'footer'      => $not_ref,
+
+    ## Entity details, which are used for constructing invoices
+    'payment_details' => $not_ref,
+    'payment_method'  => $not_ref,
+
+    ## Invoice specific
+    'payee'    => $not_ref,
+    'payor'    => $not_ref,
+    'due_days' => $not_ref,
 );
 
 sub add ( $self, @posts ) {

+ 1 - 0
lib/Trog/Log.pm

@@ -74,6 +74,7 @@ sub _dbh {
 }
 
 sub is_debug {
+    $LEVEL //= 'info';
     return $LEVEL eq 'debug';
 }
 

+ 48 - 0
lib/Trog/Routes/HTML.pm

@@ -257,6 +257,7 @@ sub index ( $query, $content = '', $i_styles = [], $i_scripts = [] ) {
     $query->{theme_dir} = Trog::Themes::td();
 
     my $to_render = $query->{template} // $landing_page;
+
     $content ||= Trog::Renderer->render( template => $to_render, data => $query, component => 1, contenttype => 'text/html' );
     return $content if ref $content eq "ARRAY";
 
@@ -937,6 +938,30 @@ sub post_delete ($query) {
     return $query->{tpsgi}->see_also( $query->{to} );
 }
 
+my %enrich = (
+    'invoice.tx' => sub {
+        my ($post,$query) = @_;
+        # TODO it's probably a performance problem doing this per post rather than only for the series entry
+        my %ret = ( entities => [ _post_helper({ form => 'entities.tx', visibility => 'public' }, [], $query->{user_acls}) ] );
+        return %ret unless ref $post->{data} eq 'ARRAY';
+
+        # Figure out the payee/payor
+        $ret{payee_entity} = List::Util::first { $_->{id} eq $post->{payee} } @{$ret{entities}};
+        $ret{payor_entity} = List::Util::first { $_->{id} eq $post->{payor} } @{$ret{entities}};
+
+        # Build total
+        my $denom;
+        my @prices = map {
+            my $price = 0;
+            ($denom, $price) = m/^Price:\s*(\D)(\d+)/mix;
+            $price;
+        } @{$post->{data}};
+        $denom //= '$';
+        $ret{total} = $denom.(List::Util::sum(@prices) // 0);
+        return %ret;
+    },
+);
+
 =head2 series
 
 Series specific view, much like the users/ route
@@ -967,6 +992,15 @@ sub series ($query) {
     #Grab the relevant tag (aclname), then pass that to posts
     my @posts = _post_helper( $query, ['series'], $query->{user_acls} );
 
+    # Enrich posts with additional data based on the template if necessary
+    if (exists $enrich{$posts[0]->{child_form}}) {
+        my $callback = $enrich{$posts[0]->{child_form}};
+        my %extra_data = $callback->($posts[0], $query);
+        foreach my $key (keys(%extra_data)) {
+            $posts[0]->{$key} = $extra_data{$key};
+        }
+    }
+
     delete $query->{id};
     delete $query->{aclname};
 
@@ -1217,6 +1251,18 @@ sub posts ( $query, $direct = 0 ) {
     my $picker = Trog::Component::EmojiPicker::render();
     return $picker if ref $picker eq 'ARRAY';
 
+    # Enrich posts with additional data based on the template if necessary
+    foreach my $poast (@posts) {
+        if (exists $enrich{$poast->{form}}) {
+            my $callback = $enrich{$poast->{form}};
+            my %extra_data = $callback->($poast, $query);
+            foreach my $key (keys(%extra_data)) {
+                $poast->{$key} = $extra_data{$key};
+            }
+        }
+    }
+
+
     #XXX the only reason this is needed is due to direct=1
     #XXX is this even used?
     my $content = Trog::Renderer->render(
@@ -1233,6 +1279,7 @@ sub posts ( $query, $direct = 0 ) {
             direct            => $direct,
             title             => $query->{title},
             author            => $query->{primary_post}{user} // $posts[0]{user},
+            primary_post      => $query->{primary_post},
             style             => $query->{style},
             posts             => \@posts,
             like              => $query->{like},
@@ -1293,6 +1340,7 @@ sub _post_helper ( $query, $tags, $acls ) {
         author       => $query->{author},
         id           => $query->{id},
         version      => $query->{version},
+        form         => $query->{form},
     );
     return map {
         my $subj = $_;

+ 4 - 0
www/templates/html/components/entity_details.tx

@@ -0,0 +1,4 @@
+Payment Method<br />
+<input id="<: $post.id :>-payment_method" class="cooltext" name="payment_method" value="<: $post.payment_method :>"></input>
+Payment Details<br />
+<input id="<: $post.id :>-payment_details" class="cooltext" name="payment_details" value="<: $post.payment_details :>" ></input>

+ 30 - 0
www/templates/html/components/forms/entities.tx

@@ -0,0 +1,30 @@
+<div class="post <: $style :>">
+    :if ( !$post.addpost ) {
+        : include "post_title.tx";
+        : include "post_tags.tx";
+
+        : if ( !$post.video_href && !$post.is_image && !$post.is_video && !$post.is_profile && $post.preview ) {
+            <img src="<: $post.preview :>" class="responsive-img" />
+        : }
+
+        <div class="postData responsive-text" id="postData-<: $post.id :>">
+            <: render_it($post.data) | mark_raw  :>
+        </div>
+    : }
+
+    : if ( $can_edit ) {
+        <div class="postedit">
+        : include "edit_head.tx";
+        <form class="Submissions" action="/post/save" method="POST" enctype="multipart/form-data">
+            Title *<br /><input required class="cooltext" type="text" name="title" placeholder="Iowa Man Destroys Moon" value="<: $post.title :>" />
+            : include "visibility.tx";
+            : include "acls.tx";
+            : include "tags.tx";
+            : include "aliases.tx";
+            : include "entity_details.tx";
+            : include "form_common.tx";
+        </form>
+        : include "edit_foot.tx";
+        </div>
+    : }
+</div>

+ 63 - 0
www/templates/html/components/forms/invoice.tx

@@ -0,0 +1,63 @@
+<div class="post <: $style :>">
+    :if ( !$post.addpost ) {
+        : include "post_title.tx";
+        : include "post_tags.tx";
+
+        : if ( !$post.video_href && !$post.is_image && !$post.is_video && !$post.is_profile && $post.preview ) {
+            <img src="<: $post.preview :>" class="responsive-img" />
+        : }
+
+        <div class="postData responsive-text" id="postData-<: $post.id :>">
+            Invoice ID# <: $post.id :><br />
+            Created: <span class="unixtimestamp"><: $post.created :></span><br />
+            Due: <span class="unixtimestamp"><: $post.created + ($post.due_days * 86400 ) :></span><br />
+            <hr />
+
+            <span style="float:left;">
+            Payee<br />
+            <: $post.payee_entity.data | mark_raw :>
+            </span>
+            <span style="float: right;">
+            Payor<br />
+            <: $post.payor_entity.data | mark_raw :>
+            </span>
+            <hr />
+
+            Payment Method:
+            <: $post.payee_entity.payment_method :><br />
+            Payment Details:
+            <: $post.payee_entity.payment_details :><br />
+
+            <hr />
+            <ul>
+            : for $post.data -> $poast {
+                <li>
+                <: render_it($poast) | mark_raw  :>
+                </li>
+            : }
+            </ul>
+            Total: <: $post.total :>
+        </div>
+    : }
+
+    : if ( $can_edit ) {
+        <div class="postedit">
+        : include "edit_head.tx";
+        <form class="Submissions" action="/post/save" method="POST" enctype="multipart/form-data">
+            Title *<br /><input required class="cooltext" type="text" name="title" placeholder="Iowa Man Destroys Moon" value="<: $post.title :>" />
+            : include "visibility.tx";
+            : include "acls.tx";
+            : include "tags.tx";
+            : include "aliases.tx";
+            : include "invoice_tofrom.tx";
+            <p>
+            Add one 'line item' per page below.<br />
+            The price will be tabulated for the total from a line beginning with 'Price:'.<br />
+            All prices must be in the same denomination.
+            </p>
+            : include "form_multi.tx";
+        </form>
+        : include "edit_foot.tx";
+        </div>
+    : }
+</div>

+ 1 - 0
www/templates/html/components/invoice_header.tx

@@ -0,0 +1 @@
+

+ 14 - 0
www/templates/html/components/invoice_tofrom.tx

@@ -0,0 +1,14 @@
+Payee<br />
+<select id="<: $post.id :>-payee" class="cooltext" name="payee">
+    : for $primary_post.entities -> $payee {
+        <option value="<: $payee.id :>"><: $payee.title :></option>
+    : }
+</select>
+Payor<br />
+<select id="<: $post.id :>-payor" class="cooltext" name="payor">
+    : for $primary_post.entities -> $payor {
+        <option value="<: $payor.id :>"><: $payor.title :></option>
+    : }
+</select>
+Due in How many Days?<br />
+<input type="text" id="<: $post.id :>-due_days" class="cooltext" name="due_days" placeholder='0'></input>

+ 1 - 1
www/templates/html/components/post_title.tx

@@ -13,7 +13,7 @@
             </select>
         </form>
         : }
-        <span id="<: $post.id :>-<: $post.version :>-time" class="responsive-hide" style="float:right;"><: $post.created :></span>
+        <span id="<: $post.id :>-<: $post.version :>-time" class="responsive-hide unixtimestamp" style="float:right;"><: $post.created :></span>
         <a href="/users/<: $post.display_name :>" class='postericon <: $post.user_class :>' title='Posted by <: $post.display_name :>'>&nbsp;</a>
     : }
 </h3>

+ 5 - 6
www/templates/html/components/posts.tx

@@ -76,13 +76,12 @@ document.addEventListener("DOMContentLoaded", function(){
         document.addEventListener("DOMContentLoaded", function(event) {
 
             // Fix post dates to be localized
-            var e = document.getElementById("<: $post.id :>-<: $post.version :>-time");
-            if (!e) {
-                return;
+            var timey = document.querySelectorAll('.unixtimestamp');
+            for (var e of timey) {
+                var d = new Date(0);
+                d.setUTCSeconds(e.innerText);
+                e.innerHTML = "&nbsp;" + d.toDateString();
             }
-            var d = new Date(0);
-            d.setUTCSeconds(e.innerText);
-            e.innerHTML = "&nbsp;" + d.toDateString();
 
             //Make the version switcher do things
             var swit = document.getElementById("<: $post.id :>-<: $post.version :>-version");