Jump to content

Invoices Are Not Sent


facilplan

Recommended Posts

Facilplan

 

I had the same issue but I do not remember if it was my fault or the email template (Unpaid Invoice). 

 

An invoice has been created for your account and is attached to this email in PDF format.
{% for invoice in invoices %}
Invoice #: {invoice.id_code}{% endfor %}

 

Make sure that the {% endfor %} is there

 

Regards

Link to comment
Share on other sites

Not sure what does your system status say? Does it have any warnings?

System status say: Unclose tag, expecting endfor on line 98 in /home/facilpla/public_html/admin/vendors/h2o/h2o/parser.php

 

Send invoices is the only thing that does not work. The welcome email and the creation of the service, it works.

Link to comment
Share on other sites

Try using the code from mine, I don't have that issue.

 

<?php
class H2o_Lexer {
    function __construct($options = array()) {
        $this->options = $options;

        $trim = '';
        if ($this->options['TRIM_TAGS'])
            $trim = '(?:\r?\n)?';

        $this->pattern = ('/\G(.*?)(?:' .
            preg_quote($this->options['BLOCK_START']). '(.*?)' .preg_quote($this->options['BLOCK_END']) . $trim . '|' .
            preg_quote($this->options['VARIABLE_START']). '(.*?)' .preg_quote($this->options['VARIABLE_END']) . '|' .
            preg_quote($this->options['COMMENT_START']). '(.*?)' .preg_quote($this->options['COMMENT_END']) . $trim . ')/sm'
        );
    }

    function tokenize($source) {
        $result = new TokenStream;
        $pos = 0;
        $matches = array();
        preg_match_all($this->pattern, $source, $matches, PREG_SET_ORDER);

        foreach ($matches as $match) {
            if ($match[1])
            $result->feed('text', $match[1], $pos);
            $tagpos = $pos + strlen($match[1]);
            if ($match[2])
            $result->feed('block', trim($match[2]), $tagpos);
            elseif ($match[3])
            $result->feed('variable', trim($match[3]), $tagpos);
            elseif ($match[4])
            $result->feed('comment', trim($match[4]), $tagpos);
            $pos += strlen($match[0]);
        }
        if ($pos < strlen($source)){
            $result->feed('text', substr($source, $pos), $pos);
        }
        $result->close();
        return $result;
    }
}

class H2o_Parser {
    var $first;
    var $storage = array();
    var $filename;
    var $runtime;
    
    function __construct($source, $filename, $runtime, $options) {
        $this->options = $options;
        //$this->source = $source;
        $this->runtime = $runtime;
        $this->filename = $filename;
        $this->first = true;
        
        $this->lexer = new H2o_Lexer($options);
        $this->tokenstream = $this->lexer->tokenize($source);
        $this->storage = array(
          'blocks' => array(),
          'templates' => array(),
          'included' => array()
        );
    }

    function &parse() {
        $until = func_get_args();
        $nodelist = new NodeList($this);
        while($token = $this->tokenstream->next()) { 
            //$token = $this->tokenstream->current();
            switch($token->type) {
                case 'text' :
                    $node = new TextNode($token->content, $token->position);
                    break;
                case 'variable' :
                    $args = H2o_Parser::parseArguments($token->content, $token->position);
                    $variable = array_shift($args);
                    $filters = $args;
                    $node = new VariableNode($variable, $filters, $token->position);
                    break;
                case 'comment' :
                    $node = new CommentNode($token->content);
                    break;
                case 'block' :
                    if (in_array($token->content, $until)) {
                        $this->token = $token;                      
                        return $nodelist;
                    }
                    @list($name, $args) = preg_split('/\s+/',$token->content, 2);
                    $node = H2o::createTag($name, $args, $this, $token->position);
                    $this->token = $token;
            }
            $this->searching = join(',',$until);
            $this->first = false;
            $nodelist->append($node);
        }

        if ($until) {
            throw new TemplateSyntaxError('Unclose tag, expecting '. $until[0]);
        }
        return $nodelist;
    }

    function skipTo($until) {
        $this->parse($until);
        return null;
    }

    # Parse arguments
    static function parseArguments($source = null, $fpos = 0){
        $parser = new ArgumentLexer($source, $fpos);
        $result = array();
        $current_buffer = &$result;
        $filter_buffer = array();
        $tokens = $parser->parse();
        foreach ($tokens as $token) {
            list($token, $data) = $token;
            if ($token == 'filter_start') {
                $filter_buffer = array();
                $current_buffer = &$filter_buffer;
            }
            elseif ($token == 'filter_end') {
                if (count($filter_buffer)) {
	
                    $i = count($result)-1;
                    if ( is_array($result[$i]) ) $result[$i]['filters'][] = $filter_buffer;
                    else $result[$i] = array(0 => $result[$i], 'filters' => array($filter_buffer));
                }
                $current_buffer = &$result;
            }
            elseif ($token == 'boolean') {
                $current_buffer[] = ($data === 'true'? true : false);
            }            
            elseif ($token == 'name') {
                $current_buffer[] = symbol($data);
            }
            elseif ($token == 'number' || $token == 'string') { 
                $current_buffer[] = $data;
            } 
            elseif ($token == 'named_argument') {
                $last = $current_buffer[count($current_buffer) - 1];
                if (!is_array($last))
                    $current_buffer[] = array();

                $namedArgs =& $current_buffer[count($current_buffer) - 1]; 
                list($name,$value) = array_map('trim', explode(':', $data, 2));
                
                # if argument value is variable mark it
                $value = self::parseArguments($value);
                $namedArgs[$name] = $value[0];
            }
            elseif( $token == 'operator') {
                $current_buffer[] = array('operator'=>$data);
            }
        }
        return $result;
    }
}

class H2O_RE {
    static $whitespace, $seperator, $parentheses, $pipe, $filter_end, $operator, $boolean, $number,  $string, $i18n_string, $name, $named_args;

    static function init() {
        $r = 'strip_regex';
        
        self::$whitespace   = '/\s+/m';
        self::$parentheses  = '/\(|\)/m';
        self::$filter_end   = '/;/';
        self::$boolean    = '/true|false/';
        self::$seperator    = '/,/';
        self::$pipe         = '/\|/';
        self::$operator     = '/\s?(>|<|>=|<=|!=|==|!|and |not |or )\s?/i';
        self::$number       = '/\d+(\.\d*)?/';
        self::$name         = '/[a-zA-Z_][a-zA-Z0-9-_]*(?:\.[a-zA-Z_0-9][a-zA-Z0-9_-]*)*/';
        
        self::$string       = '/(?:
                "([^"\\\\]*(?:\\\\.[^"\\\\]*)*)" |   # Double Quote string   
                \'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\' # Single Quote String
        )/xsm';
        self::$i18n_string  = "/_\({$r(self::$string)}\) | {$r(self::$string)}/xsm";

        self::$named_args   = "{
            ({$r(self::$name)})(?:{$r(self::$whitespace)})?
            : 
            (?:{$r(self::$whitespace)})?({$r(self::$i18n_string)}|{$r(self::$number)}|{$r(self::$name)})
        }x";
    }
}
H2O_RE::init();

class ArgumentLexer {
    private $source;
    private $match;
    private $pos = 0, $fpos, $eos;
    private $operator_map = array(
        '!' => 'not', '!='=> 'ne', '==' => 'eq', '>' => 'gt', '<' => 'lt', '<=' => 'le', '>=' => 'ge'
    );

    function __construct($source, $fpos = 0){
        if (!is_null($source))
          $this->source = $source;
        $this->fpos=$fpos;
    }

    function parse(){
        $result = array();
        $filtering = false;
        while (!$this->eos()) {
            $this->scan(H2O_RE::$whitespace);
            if (!$filtering) {
                if ($this->scan(H2O_RE::$operator)){
                    $operator = trim($this->match);
                    if(isset($this->operator_map[$operator]))
                        $operator = $this->operator_map[$operator];
                    $result[] = array('operator', $operator);
                }
                elseif ($this->scan(H2O_RE::$boolean))
                    $result[] = array('boolean', $this->match);
                elseif ($this->scan(H2O_RE::$named_args))
                    $result[] = array('named_argument', $this->match);                      
                elseif ($this->scan(H2O_RE::$name))
                    $result[] = array('name', $this->match);
                elseif ($this->scan(H2O_RE::$pipe)) {
                    $filtering = true;
                    $result[] = array('filter_start', $this->match);
                }
                elseif ($this->scan(H2O_RE::$seperator))
                    $result[] = array('separator', null);
                elseif ($this->scan(H2O_RE::$i18n_string))
                    $result[] = array('string', $this->match);
                elseif ($this->scan(H2O_RE::$number))
                    $result[] = array('number', $this->match);
                else
                    throw new TemplateSyntaxError('unexpected character in filters : "'. $this->source[$this->pos]. '" at '.$this->getPosition());
            } 
            else {
                // parse filters, with chaining and ";" as filter end character
                if ($this->scan(H2O_RE::$pipe)) {
                    $result[] = array('filter_end', null);
                    $result[] = array('filter_start', null);
                }
                elseif ($this->scan(H2O_RE::$seperator))
                    $result[] = array('separator', null);
                elseif ($this->scan(H2O_RE::$filter_end)) {
                    $result[] = array('filter_end', null);
                    $filtering = false;
                }
                elseif ($this->scan(H2O_RE::$boolean))
                    $result[] = array('boolean', $this->match);
                elseif ($this->scan(H2O_RE::$named_args))
                    $result[] = array('named_argument', $this->match);
                elseif ($this->scan(H2O_RE::$name))
                    $result[] = array('name', $this->match);
                elseif ($this->scan(H2O_RE::$i18n_string))
                    $result[] = array('string', $this->match);
                elseif ($this->scan(H2O_RE::$number))
                    $result[] = array('number', $this->match);          
                else
                    throw new TemplateSyntaxError('unexpected character in filters : "'. $this->source[$this->pos]. '" at '.$this->getPosition());
            }
        }
        // if we are still in the filter state, we add a filter_end token.
        if ($filtering)
            $result[] = array('filter_end', null);
        return $result;
    }

    # String scanner
    function scan($regexp) {
        if (preg_match($regexp . 'A', $this->source, $match, null, $this->pos)) {
            $this->match = $match[0];
            $this->pos += strlen($this->match);
            return true;
        }
        return false;
    }

    function eos() {
        return $this->pos >= strlen($this->source);
    }
    
    /**
     * return the position in the template
     */
    function getPosition() {
        return $this->fpos + $this->pos;
    }
}
?>
Link to comment
Share on other sites

Facilplan

 

I had the same issue but I do not remember if it was my fault or the email template (Unpaid Invoice). 

 

An invoice has been created for your account and is attached to this email in PDF format.

{% for invoice in invoices %}

Invoice #: {invoice.id_code}{% endfor %}

 

Make sure that the {% endfor %} is there

 

Regards

Thank you Sanecty for your answer, but I think that I don't explained properly.

When I create an invoice manually, then I can "see" "edit" "pay" options, but the Status is "Unsent". When I click the "send" button the system tells me:

Oh noes!

Unclose tag, expecting endfor on line 98 in /home/facilpla/public_html/admin/vendors/h2o/h2o/parser.php

Printing Stack Trace:

#0 /home/facilpla/public_html/admin/vendors/h2o/h2o/tags.php(112): H2o_Parser->parse('endfor', 'else')

#1 /home/facilpla/public_html/admin/vendors/h2o/h2o.php(151): For_Tag->__construct('invoice in invo...', Object(H2o_Parser), 111)

#2 /home/facilpla/public_html/admin/vendors/h2o/h2o/parser.php(89): H2o::createTag('for', 'invoice in invo...', Object(H2o_Parser), 111)

#3 /home/facilpla/public_html/admin/vendors/h2o/h2o.php(106): H2o_Parser->parse()

#4 /home/facilpla/public_html/admin/vendors/h2o/h2o.php(142): H2o->parse('Hola {contact.f...')

#5 /home/facilpla/public_html/admin/app/models/emails.php(753): H2o::parseString('Hola {contact.f...', Array)

#6 /home/facilpla/public_html/admin/app/models/emails.php(479): Emails->buildEmail('invoice_deliver...', '1', 'es_es', Array)

#7 /home/facilpla/public_html/admin/components/invoice_delivery/invoice_delivery.php(122): Emails->send('invoice_deliver...', '1', 'es_es', 'contacto@mundod...', Array, NULL, NULL, Array, Array)

#8 /home/facilpla/public_html/admin/app/controllers/admin_clients.php(294): InvoiceDelivery->deliverInvoices(Array, 'email', 'contacto@mundod...', '1', Array)

#9 /home/facilpla/public_html/admin/lib/dispatcher.php(111): AdminClients->invoices()

#10 /home/facilpla/public_html/admin/index.php(21): Dispatcher::dispatch('/admin/clients/...')

#11 {main}

 

This problem only happens in "send invoice" because the welcome message arrives correctly.

Link to comment
Share on other sites

Try using the code from mine, I don't have that issue.

 

<?php
class H2o_Lexer {
    function __construct($options = array()) {
        $this->options = $options;

        $trim = '';
        if ($this->options['TRIM_TAGS'])
            $trim = '(?:\r?\n)?';

        $this->pattern = ('/\G(.*?)(?:' .
            preg_quote($this->options['BLOCK_START']). '(.*?)' .preg_quote($this->options['BLOCK_END']) . $trim . '|' .
            preg_quote($this->options['VARIABLE_START']). '(.*?)' .preg_quote($this->options['VARIABLE_END']) . '|' .
            preg_quote($this->options['COMMENT_START']). '(.*?)' .preg_quote($this->options['COMMENT_END']) . $trim . ')/sm'
        );
    }

    function tokenize($source) {
        $result = new TokenStream;
        $pos = 0;
        $matches = array();
        preg_match_all($this->pattern, $source, $matches, PREG_SET_ORDER);

        foreach ($matches as $match) {
            if ($match[1])
            $result->feed('text', $match[1], $pos);
            $tagpos = $pos + strlen($match[1]);
            if ($match[2])
            $result->feed('block', trim($match[2]), $tagpos);
            elseif ($match[3])
            $result->feed('variable', trim($match[3]), $tagpos);
            elseif ($match[4])
            $result->feed('comment', trim($match[4]), $tagpos);
            $pos += strlen($match[0]);
        }
        if ($pos < strlen($source)){
            $result->feed('text', substr($source, $pos), $pos);
        }
        $result->close();
        return $result;
    }
}

class H2o_Parser {
    var $first;
    var $storage = array();
    var $filename;
    var $runtime;
    
    function __construct($source, $filename, $runtime, $options) {
        $this->options = $options;
        //$this->source = $source;
        $this->runtime = $runtime;
        $this->filename = $filename;
        $this->first = true;
        
        $this->lexer = new H2o_Lexer($options);
        $this->tokenstream = $this->lexer->tokenize($source);
        $this->storage = array(
          'blocks' => array(),
          'templates' => array(),
          'included' => array()
        );
    }

    function &parse() {
        $until = func_get_args();
        $nodelist = new NodeList($this);
        while($token = $this->tokenstream->next()) { 
            //$token = $this->tokenstream->current();
            switch($token->type) {
                case 'text' :
                    $node = new TextNode($token->content, $token->position);
                    break;
                case 'variable' :
                    $args = H2o_Parser::parseArguments($token->content, $token->position);
                    $variable = array_shift($args);
                    $filters = $args;
                    $node = new VariableNode($variable, $filters, $token->position);
                    break;
                case 'comment' :
                    $node = new CommentNode($token->content);
                    break;
                case 'block' :
                    if (in_array($token->content, $until)) {
                        $this->token = $token;                      
                        return $nodelist;
                    }
                    @list($name, $args) = preg_split('/\s+/',$token->content, 2);
                    $node = H2o::createTag($name, $args, $this, $token->position);
                    $this->token = $token;
            }
            $this->searching = join(',',$until);
            $this->first = false;
            $nodelist->append($node);
        }

        if ($until) {
            throw new TemplateSyntaxError('Unclose tag, expecting '. $until[0]);
        }
        return $nodelist;
    }

    function skipTo($until) {
        $this->parse($until);
        return null;
    }

    # Parse arguments
    static function parseArguments($source = null, $fpos = 0){
        $parser = new ArgumentLexer($source, $fpos);
        $result = array();
        $current_buffer = &$result;
        $filter_buffer = array();
        $tokens = $parser->parse();
        foreach ($tokens as $token) {
            list($token, $data) = $token;
            if ($token == 'filter_start') {
                $filter_buffer = array();
                $current_buffer = &$filter_buffer;
            }
            elseif ($token == 'filter_end') {
                if (count($filter_buffer)) {
	
                    $i = count($result)-1;
                    if ( is_array($result[$i]) ) $result[$i]['filters'][] = $filter_buffer;
                    else $result[$i] = array(0 => $result[$i], 'filters' => array($filter_buffer));
                }
                $current_buffer = &$result;
            }
            elseif ($token == 'boolean') {
                $current_buffer[] = ($data === 'true'? true : false);
            }            
            elseif ($token == 'name') {
                $current_buffer[] = symbol($data);
            }
            elseif ($token == 'number' || $token == 'string') { 
                $current_buffer[] = $data;
            } 
            elseif ($token == 'named_argument') {
                $last = $current_buffer[count($current_buffer) - 1];
                if (!is_array($last))
                    $current_buffer[] = array();

                $namedArgs =& $current_buffer[count($current_buffer) - 1]; 
                list($name,$value) = array_map('trim', explode(':', $data, 2));
                
                # if argument value is variable mark it
                $value = self::parseArguments($value);
                $namedArgs[$name] = $value[0];
            }
            elseif( $token == 'operator') {
                $current_buffer[] = array('operator'=>$data);
            }
        }
        return $result;
    }
}

class H2O_RE {
    static $whitespace, $seperator, $parentheses, $pipe, $filter_end, $operator, $boolean, $number,  $string, $i18n_string, $name, $named_args;

    static function init() {
        $r = 'strip_regex';
        
        self::$whitespace   = '/\s+/m';
        self::$parentheses  = '/\(|\)/m';
        self::$filter_end   = '/;/';
        self::$boolean    = '/true|false/';
        self::$seperator    = '/,/';
        self::$pipe         = '/\|/';
        self::$operator     = '/\s?(>|<|>=|<=|!=|==|!|and |not |or )\s?/i';
        self::$number       = '/\d+(\.\d*)?/';
        self::$name         = '/[a-zA-Z_][a-zA-Z0-9-_]*(?:\.[a-zA-Z_0-9][a-zA-Z0-9_-]*)*/';
        
        self::$string       = '/(?:
                "([^"\\\\]*(?:\\\\.[^"\\\\]*)*)" |   # Double Quote string   
                \'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\' # Single Quote String
        )/xsm';
        self::$i18n_string  = "/_\({$r(self::$string)}\) | {$r(self::$string)}/xsm";

        self::$named_args   = "{
            ({$r(self::$name)})(?:{$r(self::$whitespace)})?
            : 
            (?:{$r(self::$whitespace)})?({$r(self::$i18n_string)}|{$r(self::$number)}|{$r(self::$name)})
        }x";
    }
}
H2O_RE::init();

class ArgumentLexer {
    private $source;
    private $match;
    private $pos = 0, $fpos, $eos;
    private $operator_map = array(
        '!' => 'not', '!='=> 'ne', '==' => 'eq', '>' => 'gt', '<' => 'lt', '<=' => 'le', '>=' => 'ge'
    );

    function __construct($source, $fpos = 0){
        if (!is_null($source))
          $this->source = $source;
        $this->fpos=$fpos;
    }

    function parse(){
        $result = array();
        $filtering = false;
        while (!$this->eos()) {
            $this->scan(H2O_RE::$whitespace);
            if (!$filtering) {
                if ($this->scan(H2O_RE::$operator)){
                    $operator = trim($this->match);
                    if(isset($this->operator_map[$operator]))
                        $operator = $this->operator_map[$operator];
                    $result[] = array('operator', $operator);
                }
                elseif ($this->scan(H2O_RE::$boolean))
                    $result[] = array('boolean', $this->match);
                elseif ($this->scan(H2O_RE::$named_args))
                    $result[] = array('named_argument', $this->match);                      
                elseif ($this->scan(H2O_RE::$name))
                    $result[] = array('name', $this->match);
                elseif ($this->scan(H2O_RE::$pipe)) {
                    $filtering = true;
                    $result[] = array('filter_start', $this->match);
                }
                elseif ($this->scan(H2O_RE::$seperator))
                    $result[] = array('separator', null);
                elseif ($this->scan(H2O_RE::$i18n_string))
                    $result[] = array('string', $this->match);
                elseif ($this->scan(H2O_RE::$number))
                    $result[] = array('number', $this->match);
                else
                    throw new TemplateSyntaxError('unexpected character in filters : "'. $this->source[$this->pos]. '" at '.$this->getPosition());
            } 
            else {
                // parse filters, with chaining and ";" as filter end character
                if ($this->scan(H2O_RE::$pipe)) {
                    $result[] = array('filter_end', null);
                    $result[] = array('filter_start', null);
                }
                elseif ($this->scan(H2O_RE::$seperator))
                    $result[] = array('separator', null);
                elseif ($this->scan(H2O_RE::$filter_end)) {
                    $result[] = array('filter_end', null);
                    $filtering = false;
                }
                elseif ($this->scan(H2O_RE::$boolean))
                    $result[] = array('boolean', $this->match);
                elseif ($this->scan(H2O_RE::$named_args))
                    $result[] = array('named_argument', $this->match);
                elseif ($this->scan(H2O_RE::$name))
                    $result[] = array('name', $this->match);
                elseif ($this->scan(H2O_RE::$i18n_string))
                    $result[] = array('string', $this->match);
                elseif ($this->scan(H2O_RE::$number))
                    $result[] = array('number', $this->match);          
                else
                    throw new TemplateSyntaxError('unexpected character in filters : "'. $this->source[$this->pos]. '" at '.$this->getPosition());
            }
        }
        // if we are still in the filter state, we add a filter_end token.
        if ($filtering)
            $result[] = array('filter_end', null);
        return $result;
    }

    # String scanner
    function scan($regexp) {
        if (preg_match($regexp . 'A', $this->source, $match, null, $this->pos)) {
            $this->match = $match[0];
            $this->pos += strlen($this->match);
            return true;
        }
        return false;
    }

    function eos() {
        return $this->pos >= strlen($this->source);
    }
    
    /**
     * return the position in the template
     */
    function getPosition() {
        return $this->fpos + $this->pos;
    }
}
?>

Well, I tried your script but it is identical to mine and the result is the same. Is there a problem in line 98?

Link to comment
Share on other sites

Well, I tried your script but it is identical to mine and the result is the same. Is there a problem in line 98?

I'm not sure as I'm only learning to make modules (not going well at the moment haha)

 

But this is the code and it seems to be coming from above it if your right because this is to spit an error out.

 

        if ($until) {
            throw new TemplateSyntaxError('Unclose tag, expecting '. $until[0]);
        }
Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
×
×
  • Create New...